1.3.77
 
Loading...
Searching...
No Matches
Context_data.cpp
Go to the documentation of this file.
1
16#include "Context.h"
17
18using namespace helios;
19
20void Context::incrementPrimitiveDataLabelCounter(const std::string &primitive_data_label) {
21 primitive_data_label_counts[primitive_data_label]++;
22}
23
24void Context::decrementPrimitiveDataLabelCounter(const std::string &primitive_data_label) {
25 auto it = primitive_data_label_counts.find(primitive_data_label);
26 if (it != primitive_data_label_counts.end() && it->second > 0) {
27 it->second--;
28 if (it->second == 0) {
29 primitive_data_label_counts.erase(it);
30 // No primitives hold this data anymore — release the type lock so a
31 // subsequent setPrimitiveData() call may register a different type.
32 primitive_data_type_registry.erase(primitive_data_label);
33 }
34 }
35}
36
37//----------- VALUE-LEVEL CACHING CONFIGURATION ----------//
38
39void Context::enablePrimitiveDataValueCaching(const std::string &label) {
40 cached_primitive_data_labels.insert(label);
41}
42
43void Context::disablePrimitiveDataValueCaching(const std::string &label) {
44 cached_primitive_data_labels.erase(label);
45 // Clear cached values for this label
46 primitive_string_value_registry.erase(label);
47 primitive_int_value_registry.erase(label);
48 primitive_uint_value_registry.erase(label);
49}
50
51bool Context::isPrimitiveDataValueCachingEnabled(const std::string &label) const {
52 return cached_primitive_data_labels.find(label) != cached_primitive_data_labels.end();
53}
54
55void Context::enableObjectDataValueCaching(const std::string &label) {
56 cached_object_data_labels.insert(label);
57}
58
59void Context::disableObjectDataValueCaching(const std::string &label) {
60 cached_object_data_labels.erase(label);
61 // Clear cached values for this label
62 object_string_value_registry.erase(label);
63 object_int_value_registry.erase(label);
64 object_uint_value_registry.erase(label);
65}
66
67bool Context::isObjectDataValueCachingEnabled(const std::string &label) const {
68 return cached_object_data_labels.find(label) != cached_object_data_labels.end();
69}
70
71
72void Context::incrementObjectDataLabelCounter(const std::string &object_data_label) {
73 object_data_label_counts[object_data_label]++;
74}
75
76void Context::decrementObjectDataLabelCounter(const std::string &object_data_label) {
77 auto it = object_data_label_counts.find(object_data_label);
78 if (it != object_data_label_counts.end() && it->second > 0) {
79 it->second--;
80 if (it->second == 0) {
81 object_data_label_counts.erase(it);
82 // No objects hold this data anymore — release the type lock so a
83 // subsequent setObjectData() call may register a different type.
84 object_data_type_registry.erase(object_data_label);
85 }
86 }
87}
88
89// ------ Primitive Data -------- //
90
91HeliosDataType Primitive::getPrimitiveDataType(const char *label) const {
92
93#ifdef HELIOS_DEBUG
94 if (!doesPrimitiveDataExist(label)) {
95 helios_runtime_error("ERROR (Primitive::getPrimitiveDataType): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
96 }
97#endif
98
99 return primitive_data_types.at(label);
100}
101
103 const auto it = primitive_data_type_registry.find(label);
104 if (it != primitive_data_type_registry.end()) {
105 return it->second;
106 }
107 helios_runtime_error("ERROR (Context::getPrimitiveDataType): Primitive data " + std::string(label) + " does not exist.");
108 return HELIOS_TYPE_UNKNOWN; // Should never reach here, but added to avoid compiler warning
109}
110
111uint Primitive::getPrimitiveDataSize(const char *label) const {
112
113#ifdef HELIOS_DEBUG
114 if (!doesPrimitiveDataExist(label)) {
115 helios_runtime_error("ERROR (Primitive::getPrimitiveDataSize): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
116 }
117#endif
118
119 const HeliosDataType &type = primitive_data_types.at(label);
120
121 if (type == HELIOS_TYPE_INT) {
122 return primitive_data_int.at(label).size();
123 } else if (type == HELIOS_TYPE_UINT) {
124 return primitive_data_uint.at(label).size();
125 } else if (type == HELIOS_TYPE_FLOAT) {
126 return primitive_data_float.at(label).size();
127 } else if (type == HELIOS_TYPE_DOUBLE) {
128 return primitive_data_double.at(label).size();
129 } else if (type == HELIOS_TYPE_VEC2) {
130 return primitive_data_vec2.at(label).size();
131 } else if (type == HELIOS_TYPE_VEC3) {
132 return primitive_data_vec3.at(label).size();
133 } else if (type == HELIOS_TYPE_VEC4) {
134 return primitive_data_vec4.at(label).size();
135 } else if (type == HELIOS_TYPE_INT2) {
136 return primitive_data_int2.at(label).size();
137 } else if (type == HELIOS_TYPE_INT3) {
138 return primitive_data_int3.at(label).size();
139 } else if (type == HELIOS_TYPE_INT4) {
140 return primitive_data_int4.at(label).size();
141 } else if (type == HELIOS_TYPE_STRING) {
142 return primitive_data_string.at(label).size();
143 } else {
144 assert(false);
145 }
146
147 return 0;
148}
149
150void Primitive::clearPrimitiveData(const char *label) {
151
152 if (!doesPrimitiveDataExist(label)) {
153 return;
154 }
155
156 HeliosDataType type = primitive_data_types.at(label);
157
158 if (type == HELIOS_TYPE_INT) {
159 primitive_data_int.erase(label);
160 primitive_data_types.erase(label);
161 } else if (type == HELIOS_TYPE_UINT) {
162 primitive_data_uint.erase(label);
163 primitive_data_types.erase(label);
164 } else if (type == HELIOS_TYPE_FLOAT) {
165 primitive_data_float.erase(label);
166 primitive_data_types.erase(label);
167 } else if (type == HELIOS_TYPE_DOUBLE) {
168 primitive_data_double.erase(label);
169 primitive_data_types.erase(label);
170 } else if (type == HELIOS_TYPE_VEC2) {
171 primitive_data_vec2.erase(label);
172 primitive_data_types.erase(label);
173 } else if (type == HELIOS_TYPE_VEC3) {
174 primitive_data_vec3.erase(label);
175 primitive_data_types.erase(label);
176 } else if (type == HELIOS_TYPE_VEC4) {
177 primitive_data_vec4.erase(label);
178 primitive_data_types.erase(label);
179 } else if (type == HELIOS_TYPE_INT2) {
180 primitive_data_int2.erase(label);
181 primitive_data_types.erase(label);
182 } else if (type == HELIOS_TYPE_INT3) {
183 primitive_data_int3.erase(label);
184 primitive_data_types.erase(label);
185 } else if (type == HELIOS_TYPE_INT4) {
186 primitive_data_int4.erase(label);
187 primitive_data_types.erase(label);
188 } else if (type == HELIOS_TYPE_STRING) {
189 primitive_data_string.erase(label);
190 primitive_data_types.erase(label);
191 } else {
192 assert(false);
193 }
194 dirty_flag = true;
195}
196
197bool Primitive::doesPrimitiveDataExist(const char *label) const {
198 if (primitive_data_types.find(std::string(label)) == primitive_data_types.end()) {
199 return false;
200 }
201 return true;
202}
203
204std::vector<std::string> Primitive::listPrimitiveData() const {
205
206 std::vector<std::string> labels;
207 labels.reserve(primitive_data_types.size());
208
209 for (const auto &[label, type]: primitive_data_types) {
210 labels.push_back(label);
211 }
212
213 return labels;
214}
215
216HeliosDataType Context::getPrimitiveDataType(uint UUID, const char *label) const {
217#ifdef HELIOS_DEBUG
218 if (primitives.find(UUID) == primitives.end()) {
219 helios_runtime_error("ERROR (Context::getPrimitiveDataType): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
220 }
221#endif
222 return primitives.at(UUID)->getPrimitiveDataType(label);
223}
224
225uint Context::getPrimitiveDataSize(uint UUID, const char *label) const {
226#ifdef HELIOS_DEBUG
227 if (primitives.find(UUID) == primitives.end()) {
228 helios_runtime_error("ERROR (Context::getPrimitiveDataSize): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
229 }
230#endif
231 return primitives.at(UUID)->getPrimitiveDataSize(label);
232}
233
234bool Context::doesPrimitiveDataExist(uint UUID, const char *label) const {
235#ifdef HELIOS_DEBUG
236 if (primitives.find(UUID) == primitives.end()) {
237 helios_runtime_error("ERROR (Context::doesPrimitiveDataExist): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
238 }
239#endif
240 return primitives.at(UUID)->doesPrimitiveDataExist(label);
241}
242
243void Context::clearPrimitiveData(uint UUID, const char *label) {
244#ifdef HELIOS_DEBUG
245 if (primitives.find(UUID) == primitives.end()) {
246 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
247 }
248#endif
249 // Handle value registry before clearing if caching is enabled
250 std::string label_str = std::string(label);
251 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
252 HeliosDataType data_type = primitives.at(UUID)->getPrimitiveDataType(label);
253 if (data_type == HELIOS_TYPE_STRING) {
254 std::string cached_value;
255 primitives.at(UUID)->getPrimitiveData(label, cached_value);
256 decrementPrimitiveValueRegistry(label_str, cached_value);
257 } else if (data_type == HELIOS_TYPE_INT) {
258 int cached_value;
259 primitives.at(UUID)->getPrimitiveData(label, cached_value);
260 decrementPrimitiveValueRegistry(label_str, cached_value);
261 } else if (data_type == HELIOS_TYPE_UINT) {
262 uint cached_value;
263 primitives.at(UUID)->getPrimitiveData(label, cached_value);
264 decrementPrimitiveValueRegistry(label_str, cached_value);
265 }
266 }
267
268 if (primitives.at(UUID)->doesPrimitiveDataExist(label)) {
269 decrementPrimitiveDataLabelCounter(label);
270 }
271 primitives.at(UUID)->clearPrimitiveData(label);
272}
273
274void Context::clearPrimitiveData(const std::vector<uint> &UUIDs, const char *label) {
275 for (unsigned int UUID: UUIDs) {
276#ifdef HELIOS_DEBUG
277 if (primitives.find(UUID) == primitives.end()) {
278 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
279 }
280#endif
281 // Handle value registry before clearing if caching is enabled
282 std::string label_str = std::string(label);
283 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
284 HeliosDataType data_type = primitives.at(UUID)->getPrimitiveDataType(label);
285 if (data_type == HELIOS_TYPE_STRING) {
286 std::string cached_value;
287 primitives.at(UUID)->getPrimitiveData(label, cached_value);
288 decrementPrimitiveValueRegistry(label_str, cached_value);
289 } else if (data_type == HELIOS_TYPE_INT) {
290 int cached_value;
291 primitives.at(UUID)->getPrimitiveData(label, cached_value);
292 decrementPrimitiveValueRegistry(label_str, cached_value);
293 } else if (data_type == HELIOS_TYPE_UINT) {
294 uint cached_value;
295 primitives.at(UUID)->getPrimitiveData(label, cached_value);
296 decrementPrimitiveValueRegistry(label_str, cached_value);
297 }
298 }
299
300 if (primitives.at(UUID)->doesPrimitiveDataExist(label)) {
301 decrementPrimitiveDataLabelCounter(label);
302 }
303 primitives.at(UUID)->clearPrimitiveData(label);
304 }
305}
306
307void Context::clearPrimitiveData(const char *label) {
308 // Iterate over every primitive in the Context, including hidden ones, so the
309 // label is fully removed and the type registry entry is released.
310 std::string label_str(label);
311 const bool caching_enabled = isPrimitiveDataValueCachingEnabled(label_str);
312 for (const auto &[UUID, primitive]: primitives) {
313 if (!primitive->doesPrimitiveDataExist(label)) {
314 continue;
315 }
316 if (caching_enabled) {
317 HeliosDataType data_type = primitive->getPrimitiveDataType(label);
318 if (data_type == HELIOS_TYPE_STRING) {
319 std::string cached_value;
320 primitive->getPrimitiveData(label, cached_value);
321 decrementPrimitiveValueRegistry(label_str, cached_value);
322 } else if (data_type == HELIOS_TYPE_INT) {
323 int cached_value;
324 primitive->getPrimitiveData(label, cached_value);
325 decrementPrimitiveValueRegistry(label_str, cached_value);
326 } else if (data_type == HELIOS_TYPE_UINT) {
327 uint cached_value;
328 primitive->getPrimitiveData(label, cached_value);
329 decrementPrimitiveValueRegistry(label_str, cached_value);
330 }
331 }
332 decrementPrimitiveDataLabelCounter(label);
333 primitive->clearPrimitiveData(label);
334 }
335 // Guard against any reference-count drift: the label is gone after this call,
336 // so the registry entry must be released even if the counter never reached zero.
337 primitive_data_label_counts.erase(label_str);
338 primitive_data_type_registry.erase(label_str);
339}
340
341void Context::copyPrimitiveData(uint sourceUUID, uint destinationUUID) {
342
343#ifdef HELIOS_DEBUG
344 if (primitives.find(sourceUUID) == primitives.end()) {
345 helios_runtime_error("ERROR (Context::copyPrimitiveData): Source UUID of " + std::to_string(sourceUUID) + " does not exist in the Context.");
346 } else if (primitives.find(destinationUUID) == primitives.end()) {
347 helios_runtime_error("ERROR (Context::copyPrimitiveData): Destination UUID of " + std::to_string(destinationUUID) + " does not exist in the Context.");
348 }
349#endif
350
351 const auto &dest_labels = primitives.at(destinationUUID)->primitive_data_types;
352 for (const auto &[label, type]: dest_labels) {
353 decrementPrimitiveDataLabelCounter(label);
354 }
355
356 primitives.at(destinationUUID)->primitive_data_types = primitives.at(sourceUUID)->primitive_data_types;
357
358 primitives.at(destinationUUID)->primitive_data_int = primitives.at(sourceUUID)->primitive_data_int;
359 primitives.at(destinationUUID)->primitive_data_uint = primitives.at(sourceUUID)->primitive_data_uint;
360 primitives.at(destinationUUID)->primitive_data_float = primitives.at(sourceUUID)->primitive_data_float;
361 primitives.at(destinationUUID)->primitive_data_double = primitives.at(sourceUUID)->primitive_data_double;
362 primitives.at(destinationUUID)->primitive_data_vec2 = primitives.at(sourceUUID)->primitive_data_vec2;
363 primitives.at(destinationUUID)->primitive_data_vec3 = primitives.at(sourceUUID)->primitive_data_vec3;
364 primitives.at(destinationUUID)->primitive_data_vec4 = primitives.at(sourceUUID)->primitive_data_vec4;
365 primitives.at(destinationUUID)->primitive_data_int2 = primitives.at(sourceUUID)->primitive_data_int2;
366 primitives.at(destinationUUID)->primitive_data_int3 = primitives.at(sourceUUID)->primitive_data_int3;
367 primitives.at(destinationUUID)->primitive_data_int4 = primitives.at(sourceUUID)->primitive_data_int4;
368 primitives.at(destinationUUID)->primitive_data_string = primitives.at(sourceUUID)->primitive_data_string;
369
370 for (const auto &[label, type]: primitives.at(destinationUUID)->primitive_data_types) {
371 incrementPrimitiveDataLabelCounter(label);
372 }
373
374 primitives.at(destinationUUID)->dirty_flag = true;
375}
376
377void Context::renamePrimitiveData(uint UUID, const char *old_label, const char *new_label) {
378
379#ifdef HELIOS_DEBUG
380 if (primitives.find(UUID) == primitives.end()) {
381 helios_runtime_error("ERROR (Context::renamePrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
382 } else if (!primitives.at(UUID)->doesPrimitiveDataExist(old_label)) {
383 helios_runtime_error("ERROR (Context::renamePrimitiveData): Primitive data of " + std::string(old_label) + " does not exist for primitive " + std::to_string(UUID) + ".");
384 }
385#endif
386
387 duplicatePrimitiveData(UUID, old_label, new_label);
388 clearPrimitiveData(UUID, old_label);
389 primitives.at(UUID)->dirty_flag = true;
390}
391
392void Context::duplicatePrimitiveData(uint UUID, const char *old_label, const char *new_label) {
393
394#ifdef HELIOS_DEBUG
395 if (primitives.find(UUID) == primitives.end()) {
396 helios_runtime_error("ERROR (Context::duplicatePrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
397 } else if (!primitives.at(UUID)->doesPrimitiveDataExist(old_label)) {
398 helios_runtime_error("ERROR (Context::duplicatePrimitiveData): Primitive data of " + std::string(old_label) + " does not exist for primitive " + std::to_string(UUID) + ".");
399 }
400#endif
401
402 HeliosDataType type = getPrimitiveDataType(old_label);
403
404 if (!primitives.at(UUID)->doesPrimitiveDataExist(new_label)) {
405 incrementPrimitiveDataLabelCounter(new_label);
406 }
407 primitives.at(UUID)->primitive_data_types[new_label] = type;
408 if (type == HELIOS_TYPE_INT) {
409 primitives.at(UUID)->primitive_data_int[new_label] = primitives.at(UUID)->primitive_data_int.at(old_label);
410 } else if (type == HELIOS_TYPE_UINT) {
411 primitives.at(UUID)->primitive_data_uint[new_label] = primitives.at(UUID)->primitive_data_uint.at(old_label);
412 } else if (type == HELIOS_TYPE_FLOAT) {
413 primitives.at(UUID)->primitive_data_float[new_label] = primitives.at(UUID)->primitive_data_float.at(old_label);
414 } else if (type == HELIOS_TYPE_DOUBLE) {
415 primitives.at(UUID)->primitive_data_double[new_label] = primitives.at(UUID)->primitive_data_double.at(old_label);
416 } else if (type == HELIOS_TYPE_VEC2) {
417 primitives.at(UUID)->primitive_data_vec2[new_label] = primitives.at(UUID)->primitive_data_vec2.at(old_label);
418 } else if (type == HELIOS_TYPE_VEC3) {
419 primitives.at(UUID)->primitive_data_vec3[new_label] = primitives.at(UUID)->primitive_data_vec3.at(old_label);
420 } else if (type == HELIOS_TYPE_VEC4) {
421 primitives.at(UUID)->primitive_data_vec4[new_label] = primitives.at(UUID)->primitive_data_vec4.at(old_label);
422 } else if (type == HELIOS_TYPE_INT2) {
423 primitives.at(UUID)->primitive_data_int2[new_label] = primitives.at(UUID)->primitive_data_int2.at(old_label);
424 } else if (type == HELIOS_TYPE_INT3) {
425 primitives.at(UUID)->primitive_data_int3[new_label] = primitives.at(UUID)->primitive_data_int3.at(old_label);
426 } else if (type == HELIOS_TYPE_INT4) {
427 primitives.at(UUID)->primitive_data_int4[new_label] = primitives.at(UUID)->primitive_data_int4.at(old_label);
428 } else if (type == HELIOS_TYPE_STRING) {
429 primitives.at(UUID)->primitive_data_string[new_label] = primitives.at(UUID)->primitive_data_string.at(old_label);
430 } else {
431 assert(false);
432 }
433
434 primitives.at(UUID)->dirty_flag = true;
435}
436
437std::vector<std::string> Context::listPrimitiveData(uint UUID) const {
438 return getPrimitivePointer_private(UUID)->listPrimitiveData();
439}
440
441void Context::duplicatePrimitiveData(const char *existing_data_label, const char *copy_data_label) {
442 for (auto &[UUID, primitive]: primitives) {
443 if (primitive->doesPrimitiveDataExist(existing_data_label)) {
444 const HeliosDataType type = primitive->getPrimitiveDataType(existing_data_label);
445 if (!primitive->doesPrimitiveDataExist(copy_data_label)) {
446 incrementPrimitiveDataLabelCounter(copy_data_label);
447 }
448 primitive->primitive_data_types[copy_data_label] = type;
449 if (type == HELIOS_TYPE_FLOAT) {
450 primitive->primitive_data_float[copy_data_label] = primitive->primitive_data_float.at(existing_data_label);
451 } else if (type == HELIOS_TYPE_DOUBLE) {
452 primitive->primitive_data_double[copy_data_label] = primitive->primitive_data_double.at(existing_data_label);
453 } else if (type == HELIOS_TYPE_INT) {
454 primitive->primitive_data_int[copy_data_label] = primitive->primitive_data_int.at(existing_data_label);
455 } else if (type == HELIOS_TYPE_UINT) {
456 primitive->primitive_data_uint[copy_data_label] = primitive->primitive_data_uint.at(existing_data_label);
457 } else if (type == HELIOS_TYPE_VEC2) {
458 primitive->primitive_data_vec2[copy_data_label] = primitive->primitive_data_vec2.at(existing_data_label);
459 } else if (type == HELIOS_TYPE_VEC3) {
460 primitive->primitive_data_vec3[copy_data_label] = primitive->primitive_data_vec3.at(existing_data_label);
461 } else if (type == HELIOS_TYPE_VEC4) {
462 primitive->primitive_data_vec4[copy_data_label] = primitive->primitive_data_vec4.at(existing_data_label);
463 } else if (type == HELIOS_TYPE_INT2) {
464 primitive->primitive_data_int2[copy_data_label] = primitive->primitive_data_int2.at(existing_data_label);
465 } else if (type == HELIOS_TYPE_INT3) {
466 primitive->primitive_data_int3[copy_data_label] = primitive->primitive_data_int3.at(existing_data_label);
467 } else if (type == HELIOS_TYPE_STRING) {
468 primitive->primitive_data_string[copy_data_label] = primitive->primitive_data_string.at(existing_data_label);
469 }
470 primitive->dirty_flag = true;
471 }
472 }
473}
474
475void Context::calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, float &mean) const {
476 float value;
477 float sum = 0.f;
478 size_t count = 0;
479 for (uint UUID: UUIDs) {
480
481 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_FLOAT) {
482 getPrimitiveData(UUID, label.c_str(), value);
483 sum += value;
484 count++;
485 }
486 }
487
488 if (count == 0) {
489 std::cerr << "WARNING (Context::calculatePrimitiveDataMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
490 mean = 0;
491 } else {
492 mean = sum / float(count);
493 }
494}
495
496void Context::calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, double &mean) const {
497 double value;
498 double sum = 0.f;
499 size_t count = 0;
500 for (uint UUID: UUIDs) {
501
502 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_DOUBLE) {
503 getPrimitiveData(UUID, label.c_str(), value);
504 sum += value;
505 count++;
506 }
507 }
508
509 if (count == 0) {
510 std::cerr << "WARNING (Context::calculatePrimitiveDataMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
511 mean = 0;
512 } else {
513 mean = sum / float(count);
514 }
515}
516
517void Context::calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &mean) const {
518 vec2 value;
519 vec2 sum(0.f, 0.f);
520 size_t count = 0;
521 for (uint UUID: UUIDs) {
522
523 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC2) {
524 getPrimitiveData(UUID, label.c_str(), value);
525 sum = sum + value;
526 count++;
527 }
528 }
529
530 if (count == 0) {
531 std::cerr << "WARNING (Context::calculatePrimitiveDataMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
532 mean = make_vec2(0, 0);
533 } else {
534 mean = sum / float(count);
535 }
536}
537
538void Context::calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &mean) const {
539 vec3 value;
540 vec3 sum(0.f, 0.f, 0.f);
541 size_t count = 0;
542 for (uint UUID: UUIDs) {
543
544 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC3) {
545 getPrimitiveData(UUID, label.c_str(), value);
546 sum = sum + value;
547 count++;
548 }
549 }
550
551 if (count == 0) {
552 std::cerr << "WARNING (Context::calculatePrimitiveDataMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
553 mean = make_vec3(0, 0, 0);
554 } else {
555 mean = sum / float(count);
556 }
557}
558
559void Context::calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &mean) const {
560 vec4 value;
561 vec4 sum(0.f, 0.f, 0.f, 0.f);
562 size_t count = 0;
563 for (uint UUID: UUIDs) {
564
565 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC4) {
566 getPrimitiveData(UUID, label.c_str(), value);
567 sum = sum + value;
568 count++;
569 }
570 }
571
572 if (count == 0) {
573 std::cerr << "WARNING (Context::calculatePrimitiveDataMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
574 mean = make_vec4(0, 0, 0, 0);
575 } else {
576 mean = sum / float(count);
577 }
578}
579
580void Context::setObjectDataFromPrimitiveDataMean(uint objID, const std::string &label) {
581#ifdef HELIOS_DEBUG
582 if (!doesObjectExist(objID)) {
583 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
584 }
585#endif
586
587 // Get primitive UUIDs for this object
588 std::vector<uint> UUIDs = getObjectPrimitiveUUIDs(objID);
589
590 if (UUIDs.empty()) {
591 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): Object ID " + std::to_string(objID) + " has no primitive children.");
592 }
593
594 // Determine the data type by checking the first primitive that has this data
596 for (uint UUID: UUIDs) {
597 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str())) {
598 data_type = getPrimitiveDataType(label.c_str());
599 break;
600 }
601 }
602
603 if (data_type == HELIOS_TYPE_UNKNOWN) {
604 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): Primitive data '" + label + "' does not exist for any primitives in object " + std::to_string(objID) + ".");
605 }
606
607 // Validate data type is supported for mean calculation
608 if (data_type != HELIOS_TYPE_FLOAT && data_type != HELIOS_TYPE_DOUBLE && data_type != HELIOS_TYPE_VEC2 && data_type != HELIOS_TYPE_VEC3 && data_type != HELIOS_TYPE_VEC4) {
609 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): Cannot calculate mean for primitive data type. Only float, double, vec2, vec3, and vec4 are supported.");
610 }
611
612 // Calculate mean based on data type
613 if (data_type == HELIOS_TYPE_FLOAT) {
614 float value;
615 float sum = 0.f;
616 size_t count = 0;
617 for (uint UUID: UUIDs) {
618 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str())) {
619 getPrimitiveData(UUID, label.c_str(), value);
620 sum += value;
621 count++;
622 }
623 }
624 if (count == 0) {
625 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): No primitives in object " + std::to_string(objID) + " have primitive data '" + label + "'.");
626 }
627 float mean = sum / float(count);
628 setObjectData(objID, label.c_str(), mean);
629
630 } else if (data_type == HELIOS_TYPE_DOUBLE) {
631 double value;
632 double sum = 0.0;
633 size_t count = 0;
634 for (uint UUID: UUIDs) {
635 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str())) {
636 getPrimitiveData(UUID, label.c_str(), value);
637 sum += value;
638 count++;
639 }
640 }
641 if (count == 0) {
642 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): No primitives in object " + std::to_string(objID) + " have primitive data '" + label + "'.");
643 }
644 double mean = sum / double(count);
645 setObjectData(objID, label.c_str(), mean);
646
647 } else if (data_type == HELIOS_TYPE_VEC2) {
648 vec2 value;
649 vec2 sum(0.f, 0.f);
650 size_t count = 0;
651 for (uint UUID: UUIDs) {
652 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str())) {
653 getPrimitiveData(UUID, label.c_str(), value);
654 sum = sum + value;
655 count++;
656 }
657 }
658 if (count == 0) {
659 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): No primitives in object " + std::to_string(objID) + " have primitive data '" + label + "'.");
660 }
661 vec2 mean = sum / float(count);
662 setObjectData(objID, label.c_str(), mean);
663
664 } else if (data_type == HELIOS_TYPE_VEC3) {
665 vec3 value;
666 vec3 sum(0.f, 0.f, 0.f);
667 size_t count = 0;
668 for (uint UUID: UUIDs) {
669 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str())) {
670 getPrimitiveData(UUID, label.c_str(), value);
671 sum = sum + value;
672 count++;
673 }
674 }
675 if (count == 0) {
676 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): No primitives in object " + std::to_string(objID) + " have primitive data '" + label + "'.");
677 }
678 vec3 mean = sum / float(count);
679 setObjectData(objID, label.c_str(), mean);
680
681 } else if (data_type == HELIOS_TYPE_VEC4) {
682 vec4 value;
683 vec4 sum(0.f, 0.f, 0.f, 0.f);
684 size_t count = 0;
685 for (uint UUID: UUIDs) {
686 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str())) {
687 getPrimitiveData(UUID, label.c_str(), value);
688 sum = sum + value;
689 count++;
690 }
691 }
692 if (count == 0) {
693 helios_runtime_error("ERROR (Context::setObjectDataFromPrimitiveDataMean): No primitives in object " + std::to_string(objID) + " have primitive data '" + label + "'.");
694 }
695 vec4 mean = sum / float(count);
696 setObjectData(objID, label.c_str(), mean);
697 }
698}
699
700void Context::calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, float &awt_mean) const {
701 float value, A;
702 float sum = 0.f;
703 float area = 0;
704 bool nan_warning = false;
705 for (uint UUID: UUIDs) {
706
707 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_FLOAT) {
708 getPrimitiveData(UUID, label.c_str(), value);
709 A = getPrimitiveArea(UUID);
710 if (std::isnan(A)) {
711 nan_warning = true;
712 }
713 sum += value * A;
714 area += A;
715 }
716 }
717
718 if (area == 0) {
719 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
720 awt_mean = 0;
721 } else if (nan_warning) {
722 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
723 } else {
724 awt_mean = sum / area;
725 }
726}
727
728void Context::calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, double &awt_mean) const {
729 double value;
730 float A;
731 double sum = 0.f;
732 double area = 0;
733 bool nan_warning = false;
734 for (uint UUID: UUIDs) {
735
736 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_DOUBLE) {
737 getPrimitiveData(UUID, label.c_str(), value);
738 A = getPrimitiveArea(UUID);
739 if (std::isnan(A)) {
740 nan_warning = true;
741 }
742 sum += value * double(A);
743 area += A;
744 }
745 }
746
747 if (area == 0) {
748 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
749 awt_mean = 0;
750 } else if (nan_warning) {
751 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
752 } else {
753 awt_mean = sum / area;
754 }
755}
756
757void Context::calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &awt_mean) const {
758 vec2 value;
759 vec2 sum(0.f, 0.f);
760 float area = 0;
761 bool nan_warning = false;
762 for (uint UUID: UUIDs) {
763
764 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC2) {
765 getPrimitiveData(UUID, label.c_str(), value);
766 float A = getPrimitiveArea(UUID);
767 if (std::isnan(A)) {
768 nan_warning = true;
769 }
770 sum = sum + (value * A);
771 area += A;
772 }
773 }
774
775 if (area == 0) {
776 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
777 awt_mean = make_vec2(0, 0);
778 } else if (nan_warning) {
779 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
780 } else {
781 awt_mean = sum / area;
782 }
783}
784
785void Context::calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &awt_mean) const {
786 vec3 value;
787 vec3 sum(0.f, 0.f, 0.f);
788 float area = 0;
789 bool nan_warning = false;
790 for (uint UUID: UUIDs) {
791
792 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC3) {
793 getPrimitiveData(UUID, label.c_str(), value);
794 float A = getPrimitiveArea(UUID);
795 if (std::isnan(A)) {
796 nan_warning = true;
797 }
798 sum = sum + (value * A);
799 area += A;
800 }
801 }
802
803 if (area == 0) {
804 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
805 awt_mean = make_vec3(0, 0, 0);
806 } else if (nan_warning) {
807 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
808 } else {
809 awt_mean = sum / area;
810 }
811}
812
813void Context::calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &awt_mean) const {
814 vec4 value;
815 vec4 sum(0.f, 0.f, 0.f, 0.f);
816 float area = 0;
817 bool nan_warning = false;
818 for (uint UUID: UUIDs) {
819
820 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC4) {
821 getPrimitiveData(UUID, label.c_str(), value);
822 float A = getPrimitiveArea(UUID);
823 if (std::isnan(A)) {
824 nan_warning = true;
825 }
826 sum = sum + (value * A);
827 area += A;
828 }
829 }
830
831 if (area == 0) {
832 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
833 awt_mean = make_vec4(0, 0, 0, 0);
834 } else if (nan_warning) {
835 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedMean): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
836 } else {
837 awt_mean = sum / area;
838 }
839}
840
841void Context::calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, float &sum) const {
842
843 float value;
844 sum = 0.f;
845 bool added_to_sum = false;
846 for (uint UUID: UUIDs) {
847
848 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_FLOAT) {
849 getPrimitiveData(UUID, label.c_str(), value);
850 sum += value;
851 added_to_sum = true;
852 }
853 }
854
855 if (!added_to_sum) {
856 std::cerr << "WARNING (Context::calculatePrimitiveDataSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
857 }
858}
859
860void Context::calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, double &sum) const {
861
862 double value;
863 sum = 0.f;
864 bool added_to_sum = false;
865 for (uint UUID: UUIDs) {
866
867 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_DOUBLE) {
868 getPrimitiveData(UUID, label.c_str(), value);
869 sum += value;
870 added_to_sum = true;
871 }
872 }
873
874 if (!added_to_sum) {
875 std::cerr << "WARNING (Context::calculatePrimitiveDataSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
876 }
877}
878
879void Context::calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &sum) const {
880
881 vec2 value;
882 sum = make_vec2(0.f, 0.f);
883 bool added_to_sum = false;
884 for (uint UUID: UUIDs) {
885
886 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC2) {
887 getPrimitiveData(UUID, label.c_str(), value);
888 sum = sum + value;
889 added_to_sum = true;
890 }
891 }
892
893 if (!added_to_sum) {
894 std::cerr << "WARNING (Context::calculatePrimitiveDataSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
895 }
896}
897
898void Context::calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &sum) const {
899
900 vec3 value;
901 sum = make_vec3(0.f, 0.f, 0.f);
902 bool added_to_sum = false;
903 for (uint UUID: UUIDs) {
904
905 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC3) {
906 getPrimitiveData(UUID, label.c_str(), value);
907 sum = sum + value;
908 added_to_sum = true;
909 }
910 }
911
912 if (!added_to_sum) {
913 std::cerr << "WARNING (Context::calculatePrimitiveDataSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
914 }
915}
916
917void Context::calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &sum) const {
918
919 vec4 value;
920 sum = make_vec4(0.f, 0.f, 0.f, 0.f);
921 bool added_to_sum = false;
922 for (uint UUID: UUIDs) {
923
924 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC4) {
925 getPrimitiveData(UUID, label.c_str(), value);
926 sum = sum + value;
927 added_to_sum = true;
928 }
929 }
930
931 if (!added_to_sum) {
932 std::cerr << "WARNING (Context::calculatePrimitiveDataSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
933 }
934}
935
936void Context::calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, float &awt_sum) const {
937
938 float value;
939 awt_sum = 0.f;
940 bool added_to_sum = false;
941 bool nan_warning = false;
942 for (uint UUID: UUIDs) {
943
944 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_FLOAT) {
945 float area = getPrimitiveArea(UUID);
946 if (std::isnan(area)) {
947 nan_warning = true;
948 continue;
949 }
950 getPrimitiveData(UUID, label.c_str(), value);
951 awt_sum += value * area;
952 added_to_sum = true;
953 }
954 }
955
956 if (!added_to_sum) {
957 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
958 } else if (nan_warning) {
959 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
960 }
961}
962
963void Context::calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, double &awt_sum) const {
964
965 double value;
966 awt_sum = 0.f;
967 bool added_to_sum = false;
968 bool nan_warning = false;
969 for (uint UUID: UUIDs) {
970
971 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_DOUBLE) {
972 float area = getPrimitiveArea(UUID);
973 if (std::isnan(area)) {
974 nan_warning = true;
975 continue;
976 }
977 getPrimitiveData(UUID, label.c_str(), value);
978 awt_sum += value * area;
979 added_to_sum = true;
980 }
981 }
982
983 if (!added_to_sum) {
984 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
985 } else if (nan_warning) {
986 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
987 }
988}
989
990void Context::calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &awt_sum) const {
991
992 vec2 value;
993 awt_sum = make_vec2(0.f, 0.f);
994 bool added_to_sum = false;
995 bool nan_warning = false;
996 for (uint UUID: UUIDs) {
997
998 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC2) {
999 float area = getPrimitiveArea(UUID);
1000 if (std::isnan(area)) {
1001 nan_warning = true;
1002 continue;
1003 }
1004 getPrimitiveData(UUID, label.c_str(), value);
1005 awt_sum = awt_sum + value * area;
1006 added_to_sum = true;
1007 }
1008 }
1009
1010 if (!added_to_sum) {
1011 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
1012 } else if (nan_warning) {
1013 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
1014 }
1015}
1016
1017void Context::calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &awt_sum) const {
1018
1019 vec3 value;
1020 awt_sum = make_vec3(0.f, 0.f, 0.f);
1021 bool added_to_sum = false;
1022 bool nan_warning = false;
1023 for (uint UUID: UUIDs) {
1024
1025 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC3) {
1026 float area = getPrimitiveArea(UUID);
1027 if (std::isnan(area)) {
1028 nan_warning = true;
1029 continue;
1030 }
1031 getPrimitiveData(UUID, label.c_str(), value);
1032 awt_sum = awt_sum + value * area;
1033 added_to_sum = true;
1034 }
1035 }
1036
1037 if (!added_to_sum) {
1038 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
1039 } else if (nan_warning) {
1040 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
1041 }
1042}
1043
1044void Context::calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &awt_sum) const {
1045
1046 vec4 value;
1047 awt_sum = make_vec4(0.f, 0.f, 0.f, 0.F);
1048 bool added_to_sum = false;
1049 bool nan_warning = false;
1050 for (uint UUID: UUIDs) {
1051
1052 if (doesPrimitiveExist(UUID) && doesPrimitiveDataExist(UUID, label.c_str()) && getPrimitiveDataType(label.c_str()) == HELIOS_TYPE_VEC4) {
1053 float area = getPrimitiveArea(UUID);
1054 if (std::isnan(area)) {
1055 nan_warning = true;
1056 continue;
1057 }
1058 getPrimitiveData(UUID, label.c_str(), value);
1059 awt_sum = awt_sum + value * area;
1060 added_to_sum = true;
1061 }
1062 }
1063
1064 if (!added_to_sum) {
1065 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): No primitives found with primitive data of '" << label << "'. Returning a value of 0." << std::endl;
1066 } else if (nan_warning) {
1067 std::cerr << "WARNING (Context::calculatePrimitiveDataAreaWeightedSum): At least one primitive has an area of NaN and was excluded from calculations" << std::endl;
1068 }
1069}
1070
1071void Context::scalePrimitiveData(const std::vector<uint> &UUIDs, const std::string &label, float scaling_factor) {
1072
1073 uint primitives_not_exist = 0;
1074 uint primitive_data_not_exist = 0;
1075 for (uint UUID: UUIDs) {
1076 if (!doesPrimitiveExist(UUID)) {
1077 primitives_not_exist++;
1078 continue;
1079 }
1080 if (!doesPrimitiveDataExist(UUID, label.c_str())) {
1081 primitive_data_not_exist++;
1082 continue;
1083 }
1084 HeliosDataType data_type = getPrimitiveDataType(label.c_str());
1085 if (data_type == HELIOS_TYPE_FLOAT) {
1086 for (float &data: primitives.at(UUID)->primitive_data_float[label]) {
1087 data *= scaling_factor;
1088 }
1089 } else if (data_type == HELIOS_TYPE_DOUBLE) {
1090 for (double &data: primitives.at(UUID)->primitive_data_double[label]) {
1091 data *= scaling_factor;
1092 }
1093 } else if (data_type == HELIOS_TYPE_VEC2) {
1094 for (auto &data: primitives.at(UUID)->primitive_data_vec2[label]) {
1095 data.x *= scaling_factor;
1096 data.y *= scaling_factor;
1097 }
1098 } else if (data_type == HELIOS_TYPE_VEC3) {
1099 for (auto &data: primitives.at(UUID)->primitive_data_vec3[label]) {
1100 data.x *= scaling_factor;
1101 data.y *= scaling_factor;
1102 data.z *= scaling_factor;
1103 }
1104 } else if (data_type == HELIOS_TYPE_VEC4) {
1105 for (auto &data: primitives.at(UUID)->primitive_data_vec4[label]) {
1106 data.x *= scaling_factor;
1107 data.y *= scaling_factor;
1108 data.z *= scaling_factor;
1109 data.w *= scaling_factor;
1110 }
1111 } else {
1112 helios_runtime_error("ERROR (Context::scalePrimitiveData): This operation only supports primitive data of type float, double, vec2, vec3, and vec4.");
1113 }
1114 primitives.at(UUID)->dirty_flag = true;
1115 }
1116
1117 if (primitives_not_exist > 0) {
1118 std::cerr << "WARNING (Context::scalePrimitiveData): " << primitives_not_exist << " of " << UUIDs.size() << " from the input UUID vector did not exist." << std::endl;
1119 }
1120 if (primitive_data_not_exist > 0) {
1121 std::cerr << "WARNING (Context::scalePrimitiveData): Primitive data did not exist for " << primitive_data_not_exist << " primitives, and thus no scaling was applied." << std::endl;
1122 }
1123}
1124
1125void Context::scalePrimitiveData(const std::string &label, float scaling_factor) {
1126 scalePrimitiveData(getAllUUIDs(), label, scaling_factor);
1127}
1128
1129void Context::incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, int increment) {
1130
1131 WarningAggregator warnings;
1132
1133 for (uint UUID: UUIDs) {
1134
1135 if (!doesPrimitiveDataExist(UUID, label)) {
1136 helios_runtime_error("ERROR (Context::incrementPrimitiveData): Primitive data " + std::string(label) + " does not exist in the Context for primitive " + std::to_string(UUID) + ".");
1137 }
1138
1139 uint size = getPrimitiveDataSize(UUID, label);
1140
1141 if (primitives.at(UUID)->primitive_data_types.at(label) == HELIOS_TYPE_INT) {
1142 for (uint i = 0; i < size; i++) {
1143 primitives.at(UUID)->primitive_data_int.at(label).at(i) += increment;
1144 }
1145 primitives.at(UUID)->dirty_flag = true;
1146 } else {
1147 warnings.addWarning("increment_type_mismatch", "Attempted to increment primitive data for type int, but data '" + std::string(label) + "' does not have type int.");
1148 }
1149 }
1150
1151 warnings.report(std::cerr);
1152}
1153
1154void Context::incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, uint increment) {
1155
1156 WarningAggregator warnings;
1157
1158 for (uint UUID: UUIDs) {
1159
1160 if (!doesPrimitiveDataExist(UUID, label)) {
1161 helios_runtime_error("ERROR (Context::incrementPrimitiveData): Primitive data " + std::string(label) + " does not exist in the Context for primitive " + std::to_string(UUID) + ".");
1162 }
1163
1164 uint size = getPrimitiveDataSize(UUID, label);
1165
1166 if (primitives.at(UUID)->primitive_data_types.at(label) == HELIOS_TYPE_UINT) {
1167 for (uint i = 0; i < size; i++) {
1168 primitives.at(UUID)->primitive_data_uint.at(label).at(i) += increment;
1169 }
1170 primitives.at(UUID)->dirty_flag = true;
1171 } else {
1172 warnings.addWarning("increment_type_mismatch", "Attempted to increment Primitive data for type uint, but data '" + std::string(label) + "' does not have type uint.");
1173 }
1174 }
1175
1176 warnings.report(std::cerr);
1177}
1178
1179void Context::incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, float increment) {
1180
1181 WarningAggregator warnings;
1182
1183 for (uint UUID: UUIDs) {
1184
1185 if (!doesPrimitiveDataExist(UUID, label)) {
1186 helios_runtime_error("ERROR (Context::incrementPrimitiveData): Primitive data " + std::string(label) + " does not exist in the Context for primitive " + std::to_string(UUID) + ".");
1187 }
1188
1189 uint size = getPrimitiveDataSize(UUID, label);
1190
1191 if (primitives.at(UUID)->primitive_data_types.at(label) == HELIOS_TYPE_FLOAT) {
1192 for (uint i = 0; i < size; i++) {
1193 primitives.at(UUID)->primitive_data_float.at(label).at(i) += increment;
1194 }
1195 primitives.at(UUID)->dirty_flag = true;
1196 } else {
1197 warnings.addWarning("increment_type_mismatch", "Attempted to increment Primitive data for type float, but data '" + std::string(label) + "' does not have type float.");
1198 }
1199 }
1200
1201 warnings.report(std::cerr);
1202}
1203
1204void Context::incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, double increment) {
1205
1206 WarningAggregator warnings;
1207
1208 for (uint UUID: UUIDs) {
1209
1210 if (!doesPrimitiveDataExist(UUID, label)) {
1211 helios_runtime_error("ERROR (Context::incrementPrimitiveData): Primitive data " + std::string(label) + " does not exist in the Context for primitive " + std::to_string(UUID) + ".");
1212 }
1213
1214 uint size = getPrimitiveDataSize(UUID, label);
1215
1216 if (primitives.at(UUID)->primitive_data_types.at(label) == HELIOS_TYPE_DOUBLE) {
1217 for (uint i = 0; i < size; i++) {
1218 primitives.at(UUID)->primitive_data_double.at(label).at(i) += increment;
1219 }
1220 primitives.at(UUID)->dirty_flag = true;
1221 } else {
1222 warnings.addWarning("increment_type_mismatch", "Attempted to increment Primitive data for type double, but data '" + std::string(label) + "' does not have type double.");
1223 }
1224 }
1225
1226 warnings.report(std::cerr);
1227}
1228
1229void Context::aggregatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label) {
1230
1231 uint primitives_not_exist = 0;
1232 uint primitive_data_not_exist = 0;
1233
1234 float data_float = 0;
1235 double data_double = 0;
1236 uint data_uint = 0;
1237 int data_int = 0;
1238 int2 data_int2;
1239 int3 data_int3;
1240 int4 data_int4;
1241 vec2 data_vec2;
1242 vec3 data_vec3;
1243 vec4 data_vec4;
1244
1245 for (uint UUID: UUIDs) {
1246 if (!doesPrimitiveExist(UUID)) {
1247 primitives_not_exist++;
1248 continue;
1249 }
1250
1251 HeliosDataType data_type;
1252
1253 bool init_type = false;
1254 for (const auto &label: primitive_data_labels) {
1255
1256 if (!doesPrimitiveDataExist(UUID, label.c_str())) {
1257 continue;
1258 }
1259
1260 HeliosDataType data_type_current = getPrimitiveDataType(label.c_str());
1261 if (!init_type) {
1262 data_type = data_type_current;
1263 init_type = true;
1264 } else {
1265 if (data_type != data_type_current) {
1266 helios_runtime_error("ERROR (Context::aggregatePrimitiveDataSum): Primitive data types are not consistent for UUID " + std::to_string(UUID));
1267 }
1268 }
1269
1270 if (data_type_current == HELIOS_TYPE_FLOAT) {
1271 float data;
1272 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1273 data_float += data;
1274 } else if (data_type_current == HELIOS_TYPE_DOUBLE) {
1275 double data;
1276 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1277 data_double += data;
1278 } else if (data_type_current == HELIOS_TYPE_VEC2) {
1279 vec2 data;
1280 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1281 data_vec2 = data_vec2 + data;
1282 } else if (data_type_current == HELIOS_TYPE_VEC3) {
1283 vec3 data;
1284 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1285 data_vec3 = data_vec3 + data;
1286 } else if (data_type_current == HELIOS_TYPE_VEC4) {
1287 vec4 data;
1288 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1289 data_vec4 = data_vec4 + data;
1290 } else if (data_type_current == HELIOS_TYPE_INT) {
1291 int data;
1292 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1293 data_int = data_int + data;
1294 } else if (data_type_current == HELIOS_TYPE_UINT) {
1295 uint data;
1296 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1297 data_uint = data_uint + data;
1298 } else if (data_type_current == HELIOS_TYPE_INT2) {
1299 int2 data;
1300 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1301 data_int2 = data_int2 + data;
1302 } else if (data_type_current == HELIOS_TYPE_INT3) {
1303 int3 data;
1304 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1305 data_int3 = data_int3 + data;
1306 } else if (data_type_current == HELIOS_TYPE_INT4) {
1307 int4 data;
1308 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1309 data_int4 = data_int4 + data;
1310 } else {
1311 helios_runtime_error("ERROR (Context::aggregatePrimitiveDataSum): This operation is not supported for string primitive data types.");
1312 }
1313 }
1314
1315 if (!init_type) {
1316 primitive_data_not_exist++;
1317 continue;
1318 } else if (data_type == HELIOS_TYPE_FLOAT) {
1319 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_float);
1320 data_float = 0;
1321 } else if (data_type == HELIOS_TYPE_DOUBLE) {
1322 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_double);
1323 data_double = 0;
1324 } else if (data_type == HELIOS_TYPE_VEC2) {
1325 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_vec2);
1326 data_vec2 = make_vec2(0, 0);
1327 } else if (data_type == HELIOS_TYPE_VEC3) {
1328 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_vec3);
1329 data_vec3 = make_vec3(0, 0, 0);
1330 } else if (data_type == HELIOS_TYPE_VEC4) {
1331 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_vec4);
1332 data_vec4 = make_vec4(0, 0, 0, 0);
1333 } else if (data_type == HELIOS_TYPE_INT) {
1334 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int);
1335 data_int = 0;
1336 } else if (data_type == HELIOS_TYPE_UINT) {
1337 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_uint);
1338 data_uint = 0;
1339 } else if (data_type == HELIOS_TYPE_INT2) {
1340 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int2);
1341 data_int2 = make_int2(0, 0);
1342 } else if (data_type == HELIOS_TYPE_INT3) {
1343 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int3);
1344 data_int3 = make_int3(0, 0, 0);
1345 } else if (data_type == HELIOS_TYPE_INT4) {
1346 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int4);
1347 data_int4 = make_int4(0, 0, 0, 0);
1348 }
1349 }
1350
1351 if (primitives_not_exist > 0) {
1352 std::cerr << "WARNING (Context::aggregatePrimitiveDataSum): " << primitives_not_exist << " of " << UUIDs.size() << " from the input UUID vector did not exist." << std::endl;
1353 }
1354 if (primitive_data_not_exist > 0) {
1355 std::cerr << "WARNING (Context::aggregatePrimitiveDataSum): Primitive data did not exist for " << primitive_data_not_exist
1356 << " primitives, and thus no scaling summation was performed and new primitive data was not created for this primitive." << std::endl;
1357 }
1358}
1359
1360void Context::aggregatePrimitiveDataProduct(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label) {
1361
1362 uint primitives_not_exist = 0;
1363 uint primitive_data_not_exist = 0;
1364
1365 float data_float = 0;
1366 double data_double = 0;
1367 uint data_uint = 0;
1368 int data_int = 0;
1369 int2 data_int2;
1370 int3 data_int3;
1371 int4 data_int4;
1372 vec2 data_vec2;
1373 vec3 data_vec3;
1374 vec4 data_vec4;
1375
1376 for (uint UUID: UUIDs) {
1377 if (!doesPrimitiveExist(UUID)) {
1378 primitives_not_exist++;
1379 continue;
1380 }
1381
1382 HeliosDataType data_type;
1383
1384 bool init_type = false;
1385 int i = 0;
1386 for (const auto &label: primitive_data_labels) {
1387
1388 if (!doesPrimitiveDataExist(UUID, label.c_str())) {
1389 continue;
1390 }
1391
1392 HeliosDataType data_type_current = getPrimitiveDataType(label.c_str());
1393 if (!init_type) {
1394 data_type = data_type_current;
1395 init_type = true;
1396 } else {
1397 if (data_type != data_type_current) {
1398 helios_runtime_error("ERROR (Context::aggregatePrimitiveDataProduct): Primitive data types are not consistent for UUID " + std::to_string(UUID));
1399 }
1400 }
1401
1402 if (data_type_current == HELIOS_TYPE_FLOAT) {
1403 float data;
1404 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1405 if (i == 0) {
1406 data_float = data;
1407 } else {
1408 data_float *= data;
1409 }
1410 } else if (data_type_current == HELIOS_TYPE_DOUBLE) {
1411 double data;
1412 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1413 if (i == 0) {
1414 data_double *= data;
1415 } else {
1416 data_double = data;
1417 }
1418 } else if (data_type_current == HELIOS_TYPE_VEC2) {
1419 vec2 data;
1420 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1421 if (i == 0) {
1422 data_vec2.x *= data.x;
1423 data_vec2.y *= data.y;
1424 } else {
1425 data_vec2 = data;
1426 }
1427 } else if (data_type_current == HELIOS_TYPE_VEC3) {
1428 vec3 data;
1429 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1430 if (i == 0) {
1431 data_vec3.x *= data.x;
1432 data_vec3.y *= data.y;
1433 data_vec3.z *= data.z;
1434 } else {
1435 data_vec3 = data;
1436 }
1437 } else if (data_type_current == HELIOS_TYPE_VEC4) {
1438 vec4 data;
1439 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1440 if (i == 0) {
1441 data_vec4.x *= data.x;
1442 data_vec4.y *= data.y;
1443 data_vec4.z *= data.z;
1444 data_vec4.w *= data.w;
1445 } else {
1446 data_vec4 = data;
1447 }
1448 } else if (data_type_current == HELIOS_TYPE_INT) {
1449 int data;
1450 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1451 if (i == 0) {
1452 data_int = data_int * data;
1453 } else {
1454 data_int = data;
1455 }
1456 } else if (data_type_current == HELIOS_TYPE_UINT) {
1457 uint data;
1458 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1459 if (i == 0) {
1460 data_uint = data_uint * data;
1461 } else {
1462 data_uint = data;
1463 }
1464 } else if (data_type_current == HELIOS_TYPE_INT2) {
1465 int2 data;
1466 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1467 if (i == 0) {
1468 data_int2.x *= data.x;
1469 data_int2.y *= data.y;
1470 } else {
1471 data_int2 = data;
1472 }
1473 } else if (data_type_current == HELIOS_TYPE_INT3) {
1474 int3 data;
1475 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1476 if (i == 0) {
1477 data_int3.x *= data.x;
1478 data_int3.y *= data.y;
1479 data_int3.z *= data.z;
1480 } else {
1481 data_int3 = data;
1482 }
1483 } else if (data_type_current == HELIOS_TYPE_INT4) {
1484 int4 data;
1485 primitives.at(UUID)->getPrimitiveData(label.c_str(), data);
1486 if (i == 0) {
1487 data_int4.x *= data.x;
1488 data_int4.y *= data.y;
1489 data_int4.z *= data.z;
1490 data_int4.w *= data.w;
1491 } else {
1492 data_int4 = data;
1493 }
1494 } else {
1495 helios_runtime_error("ERROR (Context::aggregatePrimitiveDataProduct): This operation is not supported for string primitive data types.");
1496 }
1497 i++;
1498 }
1499
1500 if (!init_type) {
1501 primitive_data_not_exist++;
1502 continue;
1503 } else if (data_type == HELIOS_TYPE_FLOAT) {
1504 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_float);
1505 } else if (data_type == HELIOS_TYPE_DOUBLE) {
1506 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_double);
1507 } else if (data_type == HELIOS_TYPE_VEC2) {
1508 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_vec2);
1509 } else if (data_type == HELIOS_TYPE_VEC3) {
1510 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_vec3);
1511 } else if (data_type == HELIOS_TYPE_VEC4) {
1512 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_vec4);
1513 } else if (data_type == HELIOS_TYPE_INT) {
1514 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int);
1515 } else if (data_type == HELIOS_TYPE_UINT) {
1516 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_uint);
1517 } else if (data_type == HELIOS_TYPE_INT2) {
1518 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int2);
1519 } else if (data_type == HELIOS_TYPE_INT3) {
1520 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int3);
1521 } else if (data_type == HELIOS_TYPE_INT4) {
1522 setPrimitiveData(UUID, result_primitive_data_label.c_str(), data_int4);
1523 }
1524 }
1525
1526 if (primitives_not_exist > 0) {
1527 std::cerr << "WARNING (Context::aggregatePrimitiveDataProduct): " << primitives_not_exist << " of " << UUIDs.size() << " from the input UUID vector did not exist." << std::endl;
1528 }
1529 if (primitive_data_not_exist > 0) {
1530 std::cerr << "WARNING (Context::aggregatePrimitiveDataProduct): Primitive data did not exist for " << primitive_data_not_exist
1531 << " primitives, and thus no multiplication was performed and new primitive data was not created for this primitive." << std::endl;
1532 }
1533}
1534
1535
1536float Context::sumPrimitiveSurfaceArea(const std::vector<uint> &UUIDs) const {
1537
1538 bool primitive_warning = false;
1539 bool nan_warning = false;
1540 float area = 0;
1541 for (uint UUID: UUIDs) {
1542
1543 float A = getPrimitiveArea(UUID);
1544
1545 if (std::isnan(A)) {
1546 nan_warning = true;
1547 continue;
1548 }
1549
1550 if (doesPrimitiveExist(UUID)) {
1551 area += A;
1552 } else {
1553 primitive_warning = true;
1554 }
1555 }
1556
1557 if (primitive_warning) {
1558 std::cerr << "WARNING (Context::sumPrimitiveSurfaceArea): One or more primitives reference in the UUID vector did not exist." << std::endl;
1559 } else if (nan_warning) {
1560 std::cerr << "WARNING (Context::sumPrimitiveSurfaceArea): One or more primitives had an area of NaN." << std::endl;
1561 }
1562
1563 return area;
1564}
1565
1566std::vector<uint> Context::filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, float filter_value, const std::string &comparator) const {
1567
1568 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
1569 helios_runtime_error("ERROR (Context::filterPrimitivesByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
1570 }
1571
1572 std::vector<uint> UUIDs_out = UUIDs;
1573 for (std::size_t p = UUIDs.size(); p-- > 0;) {
1574 uint UUID = UUIDs_out.at(p);
1575 if (doesPrimitiveDataExist(UUID, primitive_data_label.c_str()) && getPrimitiveDataType(primitive_data_label.c_str()) == HELIOS_TYPE_FLOAT) {
1576 float data;
1577 getPrimitiveData(UUID, primitive_data_label.c_str(), data);
1578 if (comparator == "==" && data == filter_value) {
1579 continue;
1580 }
1581 if (comparator == ">" && data > filter_value) {
1582 continue;
1583 }
1584 if (comparator == "<" && data < filter_value) {
1585 continue;
1586 }
1587 if (comparator == ">=" && data >= filter_value) {
1588 continue;
1589 }
1590 if (comparator == "<=" && data <= filter_value) {
1591 continue;
1592 }
1593
1594 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1595 UUIDs_out.pop_back();
1596 } else {
1597 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1598 UUIDs_out.pop_back();
1599 }
1600 }
1601
1602 return UUIDs_out;
1603}
1604
1605std::vector<uint> Context::filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, double filter_value, const std::string &comparator) const {
1606
1607 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
1608 helios_runtime_error("ERROR (Context::filterPrimitivesByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
1609 }
1610
1611 std::vector<uint> UUIDs_out = UUIDs;
1612 for (std::size_t p = UUIDs.size(); p-- > 0;) {
1613 uint UUID = UUIDs_out.at(p);
1614 if (doesPrimitiveDataExist(UUID, primitive_data_label.c_str()) && getPrimitiveDataType(primitive_data_label.c_str()) == HELIOS_TYPE_DOUBLE) {
1615 double data;
1616 getPrimitiveData(UUID, primitive_data_label.c_str(), data);
1617 if (comparator == "==" && data == filter_value) {
1618 continue;
1619 }
1620 if (comparator == ">" && data > filter_value) {
1621 continue;
1622 }
1623 if (comparator == "<" && data < filter_value) {
1624 continue;
1625 }
1626 if (comparator == ">=" && data >= filter_value) {
1627 continue;
1628 }
1629 if (comparator == "<=" && data <= filter_value) {
1630 continue;
1631 }
1632
1633 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1634 UUIDs_out.pop_back();
1635 } else {
1636 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1637 UUIDs_out.pop_back();
1638 }
1639 }
1640
1641 return UUIDs_out;
1642}
1643
1644std::vector<uint> Context::filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, int filter_value, const std::string &comparator) const {
1645
1646 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
1647 helios_runtime_error("ERROR (Context::filterPrimitivesByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
1648 }
1649
1650 std::vector<uint> UUIDs_out = UUIDs;
1651 for (std::size_t p = UUIDs.size(); p-- > 0;) {
1652 uint UUID = UUIDs_out.at(p);
1653 if (doesPrimitiveDataExist(UUID, primitive_data_label.c_str()) && getPrimitiveDataType(primitive_data_label.c_str()) == HELIOS_TYPE_INT) {
1654 int data;
1655 getPrimitiveData(UUID, primitive_data_label.c_str(), data);
1656 if (comparator == "==" && data == filter_value) {
1657 continue;
1658 }
1659 if (comparator == ">" && data > filter_value) {
1660 continue;
1661 }
1662 if (comparator == "<" && data < filter_value) {
1663 continue;
1664 }
1665 if (comparator == ">=" && data >= filter_value) {
1666 continue;
1667 }
1668 if (comparator == "<=" && data <= filter_value) {
1669 continue;
1670 }
1671
1672 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1673 UUIDs_out.pop_back();
1674 } else {
1675 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1676 UUIDs_out.pop_back();
1677 }
1678 }
1679
1680 return UUIDs_out;
1681}
1682
1683std::vector<uint> Context::filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, uint filter_value, const std::string &comparator) const {
1684
1685 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
1686 helios_runtime_error("ERROR (Context::filterPrimitivesByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
1687 }
1688
1689 std::vector<uint> UUIDs_out = UUIDs;
1690 for (std::size_t p = UUIDs.size(); p-- > 0;) {
1691 uint UUID = UUIDs_out.at(p);
1692 if (doesPrimitiveDataExist(UUID, primitive_data_label.c_str()) && getPrimitiveDataType(primitive_data_label.c_str()) == HELIOS_TYPE_UINT) {
1693 uint data;
1694 getPrimitiveData(UUID, primitive_data_label.c_str(), data);
1695 if (comparator == "==" && data == filter_value) {
1696 continue;
1697 }
1698 if (comparator == ">" && data > filter_value) {
1699 continue;
1700 }
1701 if (comparator == "<" && data < filter_value) {
1702 continue;
1703 }
1704 if (comparator == ">=" && data >= filter_value) {
1705 continue;
1706 }
1707 if (comparator == "<=" && data <= filter_value) {
1708 continue;
1709 }
1710
1711 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1712 UUIDs_out.pop_back();
1713 } else {
1714 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1715 UUIDs_out.pop_back();
1716 }
1717 }
1718
1719 return UUIDs_out;
1720}
1721
1722std::vector<uint> Context::filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, const std::string &filter_value) const {
1723
1724 std::vector<uint> UUIDs_out = UUIDs;
1725 for (std::size_t p = UUIDs.size(); p-- > 0;) {
1726 uint UUID = UUIDs_out.at(p);
1727 if (doesPrimitiveDataExist(UUID, primitive_data_label.c_str()) && getPrimitiveDataType(primitive_data_label.c_str()) == HELIOS_TYPE_STRING) {
1728 std::string data;
1729 getPrimitiveData(UUID, primitive_data_label.c_str(), data);
1730 if (data != filter_value) {
1731 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1732 UUIDs_out.pop_back();
1733 }
1734 } else {
1735 std::swap(UUIDs_out.at(p), UUIDs_out.back());
1736 UUIDs_out.pop_back();
1737 }
1738 }
1739
1740 return UUIDs_out;
1741}
1742
1743//------ Object Data ------- //
1744
1745HeliosDataType Context::getObjectDataType(uint objID, const char *label) const {
1746#ifdef HELIOS_DEBUG
1747 if (objects.find(objID) == objects.end()) {
1748 helios_runtime_error("ERROR (Context::getObjectDataType): objID of " + std::to_string(objID) + " does not exist in the Context.");
1749 }
1750#endif
1751 return objects.at(objID)->getObjectDataType(label);
1752}
1753
1755 const auto it = object_data_type_registry.find(label);
1756 if (it != object_data_type_registry.end()) {
1757 return it->second;
1758 }
1759 helios_runtime_error("ERROR (Context::getObjectDataType): Object data " + std::string(label) + " does not exist.");
1760 return HELIOS_TYPE_UNKNOWN; // This line will never be reached, but is needed to avoid compiler warnings.
1761}
1762
1763uint Context::getObjectDataSize(uint objID, const char *label) const {
1764#ifdef HELIOS_DEBUG
1765 if (objects.find(objID) == objects.end()) {
1766 helios_runtime_error("ERROR (Context::getObjectDataSize): objID of " + std::to_string(objID) + " does not exist in the Context.");
1767 }
1768#endif
1769 return objects.at(objID)->getObjectDataSize(label);
1770}
1771
1772bool Context::doesObjectDataExist(uint objID, const char *label) const {
1773#ifdef HELIOS_DEBUG
1774 if (objects.find(objID) == objects.end()) {
1775 helios_runtime_error("ERROR (Context::doesObjectDataExist): objID of " + std::to_string(objID) + " does not exist in the Context.");
1776 }
1777#endif
1778 return objects.at(objID)->doesObjectDataExist(label);
1779}
1780
1781void Context::copyObjectData(uint source_objID, uint destination_objID) {
1782
1783#ifdef HELIOS_DEBUG
1784 if (objects.find(source_objID) == objects.end()) {
1785 helios_runtime_error("ERROR (Context::copyObjectData): Source object ID of " + std::to_string(source_objID) + " does not exist in the Context.");
1786 } else if (objects.find(destination_objID) == objects.end()) {
1787 helios_runtime_error("ERROR (Context::copyObjectData): Destination object ID of " + std::to_string(destination_objID) + " does not exist in the Context.");
1788 }
1789#endif
1790
1791 const auto &dest_labels = objects.at(destination_objID)->object_data_types;
1792 for (const auto &[label, type]: dest_labels) {
1793 decrementObjectDataLabelCounter(label);
1794 }
1795
1796 objects.at(destination_objID)->object_data_types = objects.at(source_objID)->object_data_types;
1797
1798 objects.at(destination_objID)->object_data_int = objects.at(source_objID)->object_data_int;
1799 objects.at(destination_objID)->object_data_uint = objects.at(source_objID)->object_data_uint;
1800 objects.at(destination_objID)->object_data_float = objects.at(source_objID)->object_data_float;
1801 objects.at(destination_objID)->object_data_double = objects.at(source_objID)->object_data_double;
1802 objects.at(destination_objID)->object_data_vec2 = objects.at(source_objID)->object_data_vec2;
1803 objects.at(destination_objID)->object_data_vec3 = objects.at(source_objID)->object_data_vec3;
1804 objects.at(destination_objID)->object_data_vec4 = objects.at(source_objID)->object_data_vec4;
1805 objects.at(destination_objID)->object_data_int2 = objects.at(source_objID)->object_data_int2;
1806 objects.at(destination_objID)->object_data_int3 = objects.at(source_objID)->object_data_int3;
1807 objects.at(destination_objID)->object_data_int4 = objects.at(source_objID)->object_data_int4;
1808 objects.at(destination_objID)->object_data_string = objects.at(source_objID)->object_data_string;
1809
1810 for (const auto &[lbl, type]: objects.at(destination_objID)->object_data_types) {
1811 incrementObjectDataLabelCounter(lbl);
1812 }
1813}
1814
1815void Context::duplicateObjectData(uint objID, const char *old_label, const char *new_label) {
1816
1817#ifdef HELIOS_DEBUG
1818 if (objects.find(objID) == objects.end()) {
1819 helios_runtime_error("ERROR (Context::duplicateObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
1820 } else if (!doesObjectDataExist(objID, old_label)) {
1821 helios_runtime_error("ERROR (Context::duplicateObjectData): Object ID of " + std::to_string(objID) + " does not have data with label " + std::string(old_label) + ".");
1822 }
1823#endif
1824
1825 HeliosDataType type = getObjectDataType(old_label);
1826
1827 if (!objects.at(objID)->doesObjectDataExist(new_label)) {
1828 incrementObjectDataLabelCounter(new_label);
1829 }
1830 objects.at(objID)->object_data_types[new_label] = type;
1831 if (type == HELIOS_TYPE_INT) {
1832 objects.at(objID)->object_data_int[new_label] = objects.at(objID)->object_data_int.at(old_label);
1833 } else if (type == HELIOS_TYPE_UINT) {
1834 objects.at(objID)->object_data_uint[new_label] = objects.at(objID)->object_data_uint.at(old_label);
1835 } else if (type == HELIOS_TYPE_FLOAT) {
1836 objects.at(objID)->object_data_float[new_label] = objects.at(objID)->object_data_float.at(old_label);
1837 } else if (type == HELIOS_TYPE_DOUBLE) {
1838 objects.at(objID)->object_data_double[new_label] = objects.at(objID)->object_data_double.at(old_label);
1839 } else if (type == HELIOS_TYPE_VEC2) {
1840 objects.at(objID)->object_data_vec2[new_label] = objects.at(objID)->object_data_vec2.at(old_label);
1841 } else if (type == HELIOS_TYPE_VEC3) {
1842 objects.at(objID)->object_data_vec3[new_label] = objects.at(objID)->object_data_vec3.at(old_label);
1843 } else if (type == HELIOS_TYPE_VEC4) {
1844 objects.at(objID)->object_data_vec4[new_label] = objects.at(objID)->object_data_vec4.at(old_label);
1845 } else if (type == HELIOS_TYPE_INT2) {
1846 objects.at(objID)->object_data_int2[new_label] = objects.at(objID)->object_data_int2.at(old_label);
1847 } else if (type == HELIOS_TYPE_INT3) {
1848 objects.at(objID)->object_data_int3[new_label] = objects.at(objID)->object_data_int3.at(old_label);
1849 } else if (type == HELIOS_TYPE_INT4) {
1850 objects.at(objID)->object_data_int4[new_label] = objects.at(objID)->object_data_int4.at(old_label);
1851 } else if (type == HELIOS_TYPE_STRING) {
1852 objects.at(objID)->object_data_string[new_label] = objects.at(objID)->object_data_string.at(old_label);
1853 } else {
1854 assert(false);
1855 }
1856}
1857
1858
1859void Context::renameObjectData(uint objID, const char *old_label, const char *new_label) {
1860
1861#ifdef HELIOS_DEBUG
1862 if (objects.find(objID) == objects.end()) {
1863 helios_runtime_error("ERROR (Context::renameObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
1864 } else if (!doesObjectDataExist(objID, old_label)) {
1865 helios_runtime_error("ERROR (Context::renameObjectData): Object ID of " + std::to_string(objID) + " does not have data with label " + std::string(old_label) + ".");
1866 }
1867#endif
1868
1869 duplicateObjectData(objID, old_label, new_label);
1870 clearObjectData(objID, old_label);
1871}
1872
1873void Context::clearObjectData(uint objID, const char *label) {
1874#ifdef HELIOS_DEBUG
1875 if (objects.find(objID) == objects.end()) {
1876 helios_runtime_error("ERROR (Context::clearObjectData): objID of " + std::to_string(objID) + " does not exist in the Context.");
1877 }
1878#endif
1879 // Handle value registry before clearing if caching is enabled
1880 std::string label_str = std::string(label);
1881 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
1882 HeliosDataType data_type = objects.at(objID)->getObjectDataType(label);
1883 if (data_type == HELIOS_TYPE_STRING) {
1884 std::string cached_value;
1885 objects.at(objID)->getObjectData(label, cached_value);
1886 decrementObjectValueRegistry(label_str, cached_value);
1887 } else if (data_type == HELIOS_TYPE_INT) {
1888 int cached_value;
1889 objects.at(objID)->getObjectData(label, cached_value);
1890 decrementObjectValueRegistry(label_str, cached_value);
1891 } else if (data_type == HELIOS_TYPE_UINT) {
1892 uint cached_value;
1893 objects.at(objID)->getObjectData(label, cached_value);
1894 decrementObjectValueRegistry(label_str, cached_value);
1895 }
1896 }
1897
1898 if (objects.at(objID)->doesObjectDataExist(label)) {
1899 decrementObjectDataLabelCounter(label);
1900 }
1901 objects.at(objID)->clearObjectData(label);
1902}
1903
1904void Context::clearObjectData(const std::vector<uint> &objIDs, const char *label) {
1905 std::string label_str = std::string(label);
1906 for (uint objID: objIDs) {
1907#ifdef HELIOS_DEBUG
1908 if (objects.find(objID) == objects.end()) {
1909 helios_runtime_error("ERROR (Context::clearObjectData): objID of " + std::to_string(objID) + " does not exist in the Context.");
1910 }
1911#endif
1912 // Handle value registry before clearing if caching is enabled
1913 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
1914 HeliosDataType data_type = objects.at(objID)->getObjectDataType(label);
1915 if (data_type == HELIOS_TYPE_STRING) {
1916 std::string cached_value;
1917 objects.at(objID)->getObjectData(label, cached_value);
1918 decrementObjectValueRegistry(label_str, cached_value);
1919 } else if (data_type == HELIOS_TYPE_INT) {
1920 int cached_value;
1921 objects.at(objID)->getObjectData(label, cached_value);
1922 decrementObjectValueRegistry(label_str, cached_value);
1923 } else if (data_type == HELIOS_TYPE_UINT) {
1924 uint cached_value;
1925 objects.at(objID)->getObjectData(label, cached_value);
1926 decrementObjectValueRegistry(label_str, cached_value);
1927 }
1928 }
1929
1930 if (objects.at(objID)->doesObjectDataExist(label)) {
1931 decrementObjectDataLabelCounter(label);
1932 }
1933 objects.at(objID)->clearObjectData(label);
1934 }
1935}
1936
1937void Context::clearObjectData(const char *label) {
1938 // Iterate over every object in the Context, including hidden ones, so the
1939 // label is fully removed and the type registry entry is released.
1940 std::string label_str(label);
1941 const bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
1942 for (const auto &[objID, object]: objects) {
1943 if (!object->doesObjectDataExist(label)) {
1944 continue;
1945 }
1946 if (caching_enabled) {
1947 HeliosDataType data_type = object->getObjectDataType(label);
1948 if (data_type == HELIOS_TYPE_STRING) {
1949 std::string cached_value;
1950 object->getObjectData(label, cached_value);
1951 decrementObjectValueRegistry(label_str, cached_value);
1952 } else if (data_type == HELIOS_TYPE_INT) {
1953 int cached_value;
1954 object->getObjectData(label, cached_value);
1955 decrementObjectValueRegistry(label_str, cached_value);
1956 } else if (data_type == HELIOS_TYPE_UINT) {
1957 uint cached_value;
1958 object->getObjectData(label, cached_value);
1959 decrementObjectValueRegistry(label_str, cached_value);
1960 }
1961 }
1962 decrementObjectDataLabelCounter(label);
1963 object->clearObjectData(label);
1964 }
1965 object_data_label_counts.erase(label_str);
1966 object_data_type_registry.erase(label_str);
1967}
1968
1969std::vector<std::string> Context::listObjectData(uint ObjID) const {
1970 return getObjectPointer_private(ObjID)->listObjectData();
1971}
1972
1974
1975#ifdef HELIOS_DEBUG
1976 if (!doesObjectDataExist(label)) {
1977 helios_runtime_error("ERROR (CompoundObject::getObjectDataType): Object data " + std::string(label) + " does not exist for object " + std::to_string(OID));
1978 }
1979#endif
1980
1981 return object_data_types.at(label);
1982}
1983
1984uint CompoundObject::getObjectDataSize(const char *label) const {
1985
1986#ifdef HELIOS_DEBUG
1987 if (!doesObjectDataExist(label)) {
1988 helios_runtime_error("ERROR (CompoundObject::getObjectDataSize): Object data " + std::string(label) + " does not exist for object " + std::to_string(OID));
1989 }
1990#endif
1991
1992 HeliosDataType qtype = object_data_types.at(label);
1993
1994 if (qtype == HELIOS_TYPE_INT) {
1995 return object_data_int.at(label).size();
1996 } else if (qtype == HELIOS_TYPE_UINT) {
1997 return object_data_uint.at(label).size();
1998 } else if (qtype == HELIOS_TYPE_FLOAT) {
1999 return object_data_float.at(label).size();
2000 } else if (qtype == HELIOS_TYPE_DOUBLE) {
2001 return object_data_double.at(label).size();
2002 } else if (qtype == HELIOS_TYPE_VEC2) {
2003 return object_data_vec2.at(label).size();
2004 } else if (qtype == HELIOS_TYPE_VEC3) {
2005 return object_data_vec3.at(label).size();
2006 } else if (qtype == HELIOS_TYPE_VEC4) {
2007 return object_data_vec4.at(label).size();
2008 } else if (qtype == HELIOS_TYPE_INT2) {
2009 return object_data_int2.at(label).size();
2010 } else if (qtype == HELIOS_TYPE_INT3) {
2011 return object_data_int3.at(label).size();
2012 } else if (qtype == HELIOS_TYPE_INT4) {
2013 return object_data_int4.at(label).size();
2014 } else if (qtype == HELIOS_TYPE_STRING) {
2015 return object_data_string.at(label).size();
2016 } else {
2017 assert(false);
2018 }
2019
2020 return 0;
2021}
2022
2023void CompoundObject::clearObjectData(const char *label) {
2024
2025 if (!doesObjectDataExist(label)) {
2026 return;
2027 }
2028
2029 const HeliosDataType &qtype = object_data_types.at(label);
2030
2031 if (qtype == HELIOS_TYPE_INT) {
2032 object_data_int.erase(label);
2033 object_data_types.erase(label);
2034 } else if (qtype == HELIOS_TYPE_UINT) {
2035 object_data_uint.erase(label);
2036 object_data_types.erase(label);
2037 } else if (qtype == HELIOS_TYPE_FLOAT) {
2038 object_data_float.erase(label);
2039 object_data_types.erase(label);
2040 } else if (qtype == HELIOS_TYPE_DOUBLE) {
2041 object_data_double.erase(label);
2042 object_data_types.erase(label);
2043 } else if (qtype == HELIOS_TYPE_VEC2) {
2044 object_data_vec2.erase(label);
2045 object_data_types.erase(label);
2046 } else if (qtype == HELIOS_TYPE_VEC3) {
2047 object_data_vec3.erase(label);
2048 object_data_types.erase(label);
2049 } else if (qtype == HELIOS_TYPE_VEC4) {
2050 object_data_vec4.erase(label);
2051 object_data_types.erase(label);
2052 } else if (qtype == HELIOS_TYPE_INT2) {
2053 object_data_int2.erase(label);
2054 object_data_types.erase(label);
2055 } else if (qtype == HELIOS_TYPE_INT3) {
2056 object_data_int3.erase(label);
2057 object_data_types.erase(label);
2058 } else if (qtype == HELIOS_TYPE_INT4) {
2059 object_data_int4.erase(label);
2060 object_data_types.erase(label);
2061 } else if (qtype == HELIOS_TYPE_STRING) {
2062 object_data_string.erase(label);
2063 object_data_types.erase(label);
2064 } else {
2065 assert(false);
2066 }
2067}
2068
2069bool CompoundObject::doesObjectDataExist(const char *label) const {
2070
2071 if (object_data_types.find(std::string(label)) == object_data_types.end()) {
2072 return false;
2073 } else {
2074 return true;
2075 }
2076}
2077
2078std::vector<std::string> CompoundObject::listObjectData() const {
2079
2080 std::vector<std::string> labels;
2081 labels.reserve(object_data_types.size());
2082
2083 for (const auto &[label, type]: object_data_types) {
2084 labels.push_back(label);
2085 }
2086
2087 return labels;
2088}
2089
2090std::vector<uint> Context::filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, float filter_value, const std::string &comparator) const {
2091
2092 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
2093 helios_runtime_error("ERROR (Context::filterObjectsByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
2094 }
2095
2096 std::vector<uint> objIDs_out = objIDs;
2097 for (std::size_t p = objIDs.size(); p-- > 0;) {
2098 uint objID = objIDs_out.at(p);
2099 if (doesObjectDataExist(objID, object_data_label.c_str()) && getObjectDataType(object_data_label.c_str()) == HELIOS_TYPE_FLOAT) {
2100 float data;
2101 getObjectData(objID, object_data_label.c_str(), data);
2102 if (comparator == "==" && data == filter_value) {
2103 continue;
2104 } else if (comparator == ">" && data > filter_value) {
2105 continue;
2106 } else if (comparator == "<" && data < filter_value) {
2107 continue;
2108 } else if (comparator == ">=" && data >= filter_value) {
2109 continue;
2110 } else if (comparator == "<=" && data <= filter_value) {
2111 continue;
2112 }
2113
2114 std::swap(objIDs_out.at(p), objIDs_out.back());
2115 objIDs_out.pop_back();
2116 } else {
2117 std::swap(objIDs_out.at(p), objIDs_out.back());
2118 objIDs_out.pop_back();
2119 }
2120 }
2121
2122 return objIDs_out;
2123}
2124
2125std::vector<uint> Context::filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, double filter_value, const std::string &comparator) const {
2126
2127 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
2128 helios_runtime_error("ERROR (Context::filterObjectsByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
2129 }
2130
2131 std::vector<uint> objIDs_out = objIDs;
2132 for (std::size_t p = objIDs.size(); p-- > 0;) {
2133 uint objID = objIDs_out.at(p);
2134 if (doesObjectDataExist(objID, object_data_label.c_str()) && getObjectDataType(object_data_label.c_str()) == HELIOS_TYPE_DOUBLE) {
2135 double data;
2136 getObjectData(objID, object_data_label.c_str(), data);
2137 if (comparator == "==" && data == filter_value) {
2138 continue;
2139 } else if (comparator == ">" && data > filter_value) {
2140 continue;
2141 } else if (comparator == "<" && data < filter_value) {
2142 continue;
2143 } else if (comparator == ">=" && data >= filter_value) {
2144 continue;
2145 } else if (comparator == "<=" && data <= filter_value) {
2146 continue;
2147 }
2148
2149 std::swap(objIDs_out.at(p), objIDs_out.back());
2150 objIDs_out.pop_back();
2151 } else {
2152 std::swap(objIDs_out.at(p), objIDs_out.back());
2153 objIDs_out.pop_back();
2154 }
2155 }
2156
2157 return objIDs_out;
2158}
2159
2160std::vector<uint> Context::filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, int filter_value, const std::string &comparator) const {
2161
2162 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
2163 helios_runtime_error("ERROR (Context::filterObjectsByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
2164 }
2165
2166 std::vector<uint> objIDs_out = objIDs;
2167 for (std::size_t p = objIDs.size(); p-- > 0;) {
2168 uint objID = objIDs_out.at(p);
2169 if (doesObjectDataExist(objID, object_data_label.c_str()) && getObjectDataType(object_data_label.c_str()) == HELIOS_TYPE_INT) {
2170 int data;
2171 getObjectData(objID, object_data_label.c_str(), data);
2172 if (comparator == "==" && data == filter_value) {
2173 continue;
2174 } else if (comparator == ">" && data > filter_value) {
2175 continue;
2176 } else if (comparator == "<" && data < filter_value) {
2177 continue;
2178 } else if (comparator == ">=" && data >= filter_value) {
2179 continue;
2180 } else if (comparator == "<=" && data <= filter_value) {
2181 continue;
2182 }
2183
2184 std::swap(objIDs_out.at(p), objIDs_out.back());
2185 objIDs_out.pop_back();
2186 } else {
2187 std::swap(objIDs_out.at(p), objIDs_out.back());
2188 objIDs_out.pop_back();
2189 }
2190 }
2191
2192 return objIDs_out;
2193}
2194
2195std::vector<uint> Context::filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, uint filter_value, const std::string &comparator) const {
2196
2197 if (comparator != "==" && comparator != ">" && comparator != "<" && comparator != ">=" && comparator != "<=") {
2198 helios_runtime_error("ERROR (Context::filterObjectsByData): Invalid comparator. Must be one of '==', '>', '<', '>=', or '<='.");
2199 }
2200
2201 std::vector<uint> objIDs_out = objIDs;
2202 for (std::size_t p = objIDs.size(); p-- > 0;) {
2203 uint objID = objIDs_out.at(p);
2204 if (doesObjectDataExist(objID, object_data_label.c_str()) && getObjectDataType(object_data_label.c_str()) == HELIOS_TYPE_UINT) {
2205 uint data;
2206 getObjectData(objID, object_data_label.c_str(), data);
2207 if (comparator == "==" && data == filter_value) {
2208 continue;
2209 } else if (comparator == ">" && data > filter_value) {
2210 continue;
2211 } else if (comparator == "<" && data < filter_value) {
2212 continue;
2213 } else if (comparator == ">=" && data >= filter_value) {
2214 continue;
2215 } else if (comparator == "<=" && data <= filter_value) {
2216 continue;
2217 }
2218
2219 std::swap(objIDs_out.at(p), objIDs_out.back());
2220 objIDs_out.pop_back();
2221 } else {
2222 std::swap(objIDs_out.at(p), objIDs_out.back());
2223 objIDs_out.pop_back();
2224 }
2225 }
2226
2227 return objIDs_out;
2228}
2229
2230std::vector<uint> Context::filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, const std::string &filter_value) const {
2231
2232 std::vector<uint> objIDs_out = objIDs;
2233 for (std::size_t p = objIDs.size(); p-- > 0;) {
2234 uint objID = objIDs_out.at(p);
2235 if (doesObjectDataExist(objID, object_data_label.c_str()) && getObjectDataType(object_data_label.c_str()) == HELIOS_TYPE_STRING) {
2236 std::string data;
2237 getObjectData(objID, object_data_label.c_str(), data);
2238 if (data != filter_value) {
2239 std::swap(objIDs_out.at(p), objIDs_out.back());
2240 objIDs_out.pop_back();
2241 }
2242 } else {
2243 std::swap(objIDs_out.at(p), objIDs_out.back());
2244 objIDs_out.pop_back();
2245 }
2246 }
2247
2248 return objIDs_out;
2249}
2250
2251// -------- Global Data ---------- //
2252
2253void Context::renameGlobalData(const char *old_label, const char *new_label) {
2254
2255 if (!doesGlobalDataExist(old_label)) {
2256 helios_runtime_error("ERROR (Context::duplicateGlobalData): Global data " + std::string(old_label) + " does not exist in the Context.");
2257 }
2258
2259 duplicateGlobalData(old_label, new_label);
2260 clearGlobalData(old_label);
2261}
2262
2263void Context::duplicateGlobalData(const char *old_label, const char *new_label) {
2264
2265 if (!doesGlobalDataExist(old_label)) {
2266 helios_runtime_error("ERROR (Context::duplicateGlobalData): Global data " + std::string(old_label) + " does not exist in the Context.");
2267 }
2268
2269 HeliosDataType type = getGlobalDataType(old_label);
2270
2271 if (type == HELIOS_TYPE_INT) {
2272 std::vector<int> gdata;
2273 getGlobalData(old_label, gdata);
2274 setGlobalData(new_label, gdata);
2275 } else if (type == HELIOS_TYPE_UINT) {
2276 std::vector<uint> gdata;
2277 getGlobalData(old_label, gdata);
2278 setGlobalData(new_label, gdata);
2279 } else if (type == HELIOS_TYPE_FLOAT) {
2280 std::vector<float> gdata;
2281 getGlobalData(old_label, gdata);
2282 setGlobalData(new_label, gdata);
2283 } else if (type == HELIOS_TYPE_DOUBLE) {
2284 std::vector<double> gdata;
2285 getGlobalData(old_label, gdata);
2286 setGlobalData(new_label, gdata);
2287 } else if (type == HELIOS_TYPE_VEC2) {
2288 std::vector<vec2> gdata;
2289 getGlobalData(old_label, gdata);
2290 setGlobalData(new_label, gdata);
2291 } else if (type == HELIOS_TYPE_VEC3) {
2292 std::vector<vec3> gdata;
2293 getGlobalData(old_label, gdata);
2294 setGlobalData(new_label, gdata);
2295 } else if (type == HELIOS_TYPE_VEC4) {
2296 std::vector<vec4> gdata;
2297 getGlobalData(old_label, gdata);
2298 setGlobalData(new_label, gdata);
2299 } else if (type == HELIOS_TYPE_INT2) {
2300 std::vector<int2> gdata;
2301 getGlobalData(old_label, gdata);
2302 setGlobalData(new_label, gdata);
2303 } else if (type == HELIOS_TYPE_INT3) {
2304 std::vector<int3> gdata;
2305 getGlobalData(old_label, gdata);
2306 setGlobalData(new_label, gdata);
2307 } else if (type == HELIOS_TYPE_INT4) {
2308 std::vector<int4> gdata;
2309 getGlobalData(old_label, gdata);
2310 setGlobalData(new_label, gdata);
2311 } else if (type == HELIOS_TYPE_STRING) {
2312 std::vector<std::string> gdata;
2313 getGlobalData(old_label, gdata);
2314 setGlobalData(new_label, gdata);
2315 } else {
2316 assert(false);
2317 }
2318}
2319
2320void Context::clearGlobalData(const char *label) {
2321
2322 if (doesGlobalDataExist(label)) {
2323 globaldata.erase(label);
2324 }
2325}
2326
2328
2329 if (!doesGlobalDataExist(label)) {
2330 helios_runtime_error("ERROR (Context::getGlobalDataType): Global data " + std::string(label) + " does not exist in the Context.");
2331 }
2332
2333 return globaldata.at(label).type;
2334}
2335
2336size_t Context::getGlobalDataSize(const char *label) const {
2337
2338 if (!doesGlobalDataExist(label)) {
2339 helios_runtime_error("ERROR (Context::getGlobalDataSize): Global data " + std::string(label) + " does not exist in the Context.");
2340 }
2341
2342 return globaldata.at(label).size;
2343}
2344
2345uint64_t Context::getGlobalDataVersion(const char *label) const {
2346
2347 if (!doesGlobalDataExist(label)) {
2348 return 0; // Return 0 for non-existent data (consistent with version = 0 initialization)
2349 }
2350
2351 return globaldata.at(label).version;
2352}
2353
2354std::vector<std::string> Context::listGlobalData() const {
2355
2356 std::vector<std::string> labels;
2357 labels.reserve(globaldata.size());
2358 for (const auto &[label, data]: globaldata) {
2359 labels.push_back(label);
2360 }
2361
2362 return labels;
2363}
2364
2365std::vector<std::string> Context::listAllPrimitiveDataLabels() const {
2366 std::vector<std::string> labels;
2367 labels.reserve(primitive_data_label_counts.size());
2368 for (const auto &[label, count]: primitive_data_label_counts) {
2369 if (count > 0) {
2370 labels.push_back(label);
2371 }
2372 }
2373 return labels;
2374}
2375
2376
2377std::vector<std::string> Context::listAllObjectDataLabels() const {
2378 std::vector<std::string> labels;
2379 labels.reserve(object_data_label_counts.size());
2380 for (const auto &[label, count]: object_data_label_counts) {
2381 if (count > 0) {
2382 labels.push_back(label);
2383 }
2384 }
2385 return labels;
2386}
2387
2388bool Context::doesGlobalDataExist(const char *label) const {
2389 return globaldata.find(std::string(label)) != globaldata.end();
2390}
2391
2392void Context::incrementGlobalData(const char *label, int increment) {
2393
2394 if (!doesGlobalDataExist(label)) {
2395 helios_runtime_error("ERROR (Context::incrementGlobalData): Global data " + std::string(label) + " does not exist in the Context.");
2396 }
2397
2398 uint size = getGlobalDataSize(label);
2399
2400 if (globaldata.at(label).type == HELIOS_TYPE_INT) {
2401 for (uint i = 0; i < size; i++) {
2402 globaldata.at(label).global_data_int.at(i) += increment;
2403 }
2404 } else {
2405 std::cerr << "WARNING (Context::incrementGlobalData): Attempted to increment global data for type int, but data '" << label << "' does not have type int." << std::endl;
2406 }
2407}
2408
2409void Context::incrementGlobalData(const char *label, uint increment) {
2410
2411 if (!doesGlobalDataExist(label)) {
2412 helios_runtime_error("ERROR (Context::incrementGlobalData): Global data " + std::string(label) + " does not exist in the Context.");
2413 }
2414
2415 uint size = getGlobalDataSize(label);
2416
2417 if (globaldata.at(label).type == HELIOS_TYPE_UINT) {
2418 for (uint i = 0; i < size; i++) {
2419 globaldata.at(label).global_data_uint.at(i) += increment;
2420 }
2421 } else {
2422 std::cerr << "WARNING (Context::incrementGlobalData): Attempted to increment global data for type uint, but data '" << label << "' does not have type uint." << std::endl;
2423 }
2424}
2425
2426void Context::incrementGlobalData(const char *label, float increment) {
2427
2428 if (!doesGlobalDataExist(label)) {
2429 helios_runtime_error("ERROR (Context::incrementGlobalData): Global data " + std::string(label) + " does not exist in the Context.");
2430 }
2431
2432 uint size = getGlobalDataSize(label);
2433
2434 if (globaldata.at(label).type == HELIOS_TYPE_FLOAT) {
2435 for (uint i = 0; i < size; i++) {
2436 globaldata.at(label).global_data_float.at(i) += increment;
2437 }
2438 } else {
2439 std::cerr << "WARNING (Context::incrementGlobalData): Attempted to increment global data for type float, but data '" << label << "' does not have type float." << std::endl;
2440 }
2441}
2442
2443void Context::incrementGlobalData(const char *label, double increment) {
2444
2445 if (!doesGlobalDataExist(label)) {
2446 helios_runtime_error("ERROR (Context::incrementGlobalData): Global data " + std::string(label) + " does not exist in the Context.");
2447 }
2448
2449 uint size = getGlobalDataSize(label);
2450
2451 if (globaldata.at(label).type == HELIOS_TYPE_DOUBLE) {
2452 for (uint i = 0; i < size; i++) {
2453 globaldata.at(label).global_data_double.at(i) += increment;
2454 }
2455 } else {
2456 std::cerr << "WARNING (Context::incrementGlobalData): Attempted to increment global data for type double, but data '" << label << "' does not have type double." << std::endl;
2457 }
2458}
2459
2460std::string Context::dataTypeToString(HeliosDataType type) const {
2461 switch (type) {
2462 case HELIOS_TYPE_INT:
2463 return "int";
2464 case HELIOS_TYPE_UINT:
2465 return "uint";
2466 case HELIOS_TYPE_FLOAT:
2467 return "float";
2468 case HELIOS_TYPE_DOUBLE:
2469 return "double";
2470 case HELIOS_TYPE_VEC2:
2471 return "vec2";
2472 case HELIOS_TYPE_VEC3:
2473 return "vec3";
2474 case HELIOS_TYPE_VEC4:
2475 return "vec4";
2476 case HELIOS_TYPE_INT2:
2477 return "int2";
2478 case HELIOS_TYPE_INT3:
2479 return "int3";
2480 case HELIOS_TYPE_INT4:
2481 return "int4";
2482 case HELIOS_TYPE_STRING:
2483 return "string";
2484 case HELIOS_TYPE_BOOL:
2485 return "bool";
2487 return "unknown";
2488 default:
2489 return "undefined";
2490 }
2491}
2492
2493bool Context::isTypeCastingSupported(HeliosDataType from_type, HeliosDataType to_type) const {
2494 // Support casting between numeric types only
2495 const std::set<HeliosDataType> numeric_types = {HELIOS_TYPE_INT, HELIOS_TYPE_UINT, HELIOS_TYPE_FLOAT, HELIOS_TYPE_DOUBLE};
2496
2497 return (numeric_types.count(from_type) > 0 && numeric_types.count(to_type) > 0);
2498}