1.3.72
 
Loading...
Searching...
No Matches
Context.h
Go to the documentation of this file.
1
16#ifndef HELIOS_CONTEXT
17#define HELIOS_CONTEXT
18
19#include <set>
20#include <unordered_set>
21#include <utility>
22
23#include "global.h"
24
26
28namespace helios {
29
30 class Context; // forward declaration of Context class
31
41
71
73 class Texture {
74 public:
76 Texture() = default;
77
79
82 explicit Texture(const char *texture_file);
83
85 [[nodiscard]] std::string getTextureFile() const;
86
88 [[nodiscard]] int2 getImageResolution() const;
89
91 [[nodiscard]] bool hasTransparencyChannel() const;
92
94 [[nodiscard]] const std::vector<std::vector<bool>> *getTransparencyData() const;
95
97
101 [[nodiscard]] float getSolidFraction(const std::vector<vec2> &uvs);
102
103 private:
104 std::string filename;
105 bool hastransparencychannel{};
106 std::vector<std::vector<bool>> transparencydata;
107 int2 image_resolution;
108 float solidfraction{};
109 std::unordered_map<PixelUVKey, float, PixelUVKeyHash> solidFracCache;
110
117 [[nodiscard]] float computeSolidFraction(const std::vector<vec2> &uvs) const;
118 };
119
121
129 struct Material {
132
134 std::string label;
135
138
140 std::string texture_file;
141
143
145
147
150
152
154
156 std::map<std::string, HeliosDataType> material_data_types;
158 std::map<std::string, std::vector<int>> material_data_int;
160 std::map<std::string, std::vector<uint>> material_data_uint;
162 std::map<std::string, std::vector<float>> material_data_float;
164 std::map<std::string, std::vector<double>> material_data_double;
166 std::map<std::string, std::vector<vec2>> material_data_vec2;
168 std::map<std::string, std::vector<vec3>> material_data_vec3;
170 std::map<std::string, std::vector<vec4>> material_data_vec4;
172 std::map<std::string, std::vector<int2>> material_data_int2;
174 std::map<std::string, std::vector<int3>> material_data_int3;
176 std::map<std::string, std::vector<int4>> material_data_int4;
178 std::map<std::string, std::vector<std::string>> material_data_string;
180 std::map<std::string, std::vector<bool>> material_data_bool;
181
185
187 Material(uint ID, const std::string &lbl, const RGBAcolor &c, const std::string &tex, bool override, uint twosided = 1) :
188 materialID(ID), label(lbl), color(c), texture_file(tex), texture_color_overridden(override), twosided_flag(twosided), reference_count(0) {
189 }
190
191 //-------- Material Data Methods ---------- //
192
194
199 template<typename T>
200 void setMaterialData(const char *label, const T &data) {
201 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
202 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
203 "Material::setMaterialData() was called with an unsupported type.");
204
205 if constexpr (std::is_same_v<T, int>) {
206 material_data_int[label] = {data};
208 } else if constexpr (std::is_same_v<T, uint>) {
209 material_data_uint[label] = {data};
211 } else if constexpr (std::is_same_v<T, float>) {
212 material_data_float[label] = {data};
214 } else if constexpr (std::is_same_v<T, double>) {
215 material_data_double[label] = {data};
217 } else if constexpr (std::is_same_v<T, vec2>) {
218 material_data_vec2[label] = {data};
220 } else if constexpr (std::is_same_v<T, vec3>) {
221 material_data_vec3[label] = {data};
223 } else if constexpr (std::is_same_v<T, vec4>) {
224 material_data_vec4[label] = {data};
226 } else if constexpr (std::is_same_v<T, int2>) {
227 material_data_int2[label] = {data};
229 } else if constexpr (std::is_same_v<T, int3>) {
230 material_data_int3[label] = {data};
232 } else if constexpr (std::is_same_v<T, int4>) {
233 material_data_int4[label] = {data};
235 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
236 material_data_string[label] = {data};
238 }
239 }
240
242
247 template<typename T>
248 void setMaterialData(const char *label, const std::vector<T> &data) {
249 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
250 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
251 "Material::setMaterialData() was called with an unsupported type.");
252
253 if constexpr (std::is_same_v<T, int>) {
254 material_data_int[label] = data;
256 } else if constexpr (std::is_same_v<T, uint>) {
259 } else if constexpr (std::is_same_v<T, float>) {
262 } else if constexpr (std::is_same_v<T, double>) {
265 } else if constexpr (std::is_same_v<T, vec2>) {
268 } else if constexpr (std::is_same_v<T, vec3>) {
271 } else if constexpr (std::is_same_v<T, vec4>) {
274 } else if constexpr (std::is_same_v<T, int2>) {
277 } else if constexpr (std::is_same_v<T, int3>) {
280 } else if constexpr (std::is_same_v<T, int4>) {
283 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
286 }
287 }
288
290
295 template<typename T>
296 void getMaterialData(const char *label, T &data) const {
298 helios_runtime_error("ERROR (Material::getMaterialData): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
299 }
300 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
301 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
302 "Material::getMaterialData() was called with an unsupported type.");
303
305
306 if constexpr (std::is_same_v<T, int>) {
307 if (type == HELIOS_TYPE_INT) {
308 data = material_data_int.at(label).front();
309 } else {
310 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int.");
311 }
312 } else if constexpr (std::is_same_v<T, uint>) {
313 if (type == HELIOS_TYPE_UINT) {
314 data = material_data_uint.at(label).front();
315 } else {
316 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type uint, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type uint.");
317 }
318 } else if constexpr (std::is_same_v<T, float>) {
319 if (type == HELIOS_TYPE_FLOAT) {
320 data = material_data_float.at(label).front();
321 } else {
322 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type float, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type float.");
323 }
324 } else if constexpr (std::is_same_v<T, double>) {
325 if (type == HELIOS_TYPE_DOUBLE) {
326 data = material_data_double.at(label).front();
327 } else {
328 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type double, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type double.");
329 }
330 } else if constexpr (std::is_same_v<T, vec2>) {
331 if (type == HELIOS_TYPE_VEC2) {
332 data = material_data_vec2.at(label).front();
333 } else {
334 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec2.");
335 }
336 } else if constexpr (std::is_same_v<T, vec3>) {
337 if (type == HELIOS_TYPE_VEC3) {
338 data = material_data_vec3.at(label).front();
339 } else {
340 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec3.");
341 }
342 } else if constexpr (std::is_same_v<T, vec4>) {
343 if (type == HELIOS_TYPE_VEC4) {
344 data = material_data_vec4.at(label).front();
345 } else {
346 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec4.");
347 }
348 } else if constexpr (std::is_same_v<T, int2>) {
349 if (type == HELIOS_TYPE_INT2) {
350 data = material_data_int2.at(label).front();
351 } else {
352 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int2.");
353 }
354 } else if constexpr (std::is_same_v<T, int3>) {
355 if (type == HELIOS_TYPE_INT3) {
356 data = material_data_int3.at(label).front();
357 } else {
358 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int3.");
359 }
360 } else if constexpr (std::is_same_v<T, int4>) {
361 if (type == HELIOS_TYPE_INT4) {
362 data = material_data_int4.at(label).front();
363 } else {
364 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int4.");
365 }
366 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
367 if (type == HELIOS_TYPE_STRING) {
368 data = material_data_string.at(label).front();
369 } else {
370 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type string, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type string.");
371 }
372 }
373 }
374
376
381 template<typename T>
382 void getMaterialData(const char *label, std::vector<T> &data) const {
384 helios_runtime_error("ERROR (Material::getMaterialData): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
385 }
386 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
387 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
388 "Material::getMaterialData() was called with an unsupported type.");
389
391
392 if constexpr (std::is_same_v<T, int>) {
393 if (type == HELIOS_TYPE_INT) {
394 data = material_data_int.at(label);
395 } else {
396 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int.");
397 }
398 } else if constexpr (std::is_same_v<T, uint>) {
399 if (type == HELIOS_TYPE_UINT) {
400 data = material_data_uint.at(label);
401 } else {
402 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type uint, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type uint.");
403 }
404 } else if constexpr (std::is_same_v<T, float>) {
405 if (type == HELIOS_TYPE_FLOAT) {
406 data = material_data_float.at(label);
407 } else {
408 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type float, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type float.");
409 }
410 } else if constexpr (std::is_same_v<T, double>) {
411 if (type == HELIOS_TYPE_DOUBLE) {
412 data = material_data_double.at(label);
413 } else {
414 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type double, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type double.");
415 }
416 } else if constexpr (std::is_same_v<T, vec2>) {
417 if (type == HELIOS_TYPE_VEC2) {
418 data = material_data_vec2.at(label);
419 } else {
420 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec2.");
421 }
422 } else if constexpr (std::is_same_v<T, vec3>) {
423 if (type == HELIOS_TYPE_VEC3) {
424 data = material_data_vec3.at(label);
425 } else {
426 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec3.");
427 }
428 } else if constexpr (std::is_same_v<T, vec4>) {
429 if (type == HELIOS_TYPE_VEC4) {
430 data = material_data_vec4.at(label);
431 } else {
432 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec4.");
433 }
434 } else if constexpr (std::is_same_v<T, int2>) {
435 if (type == HELIOS_TYPE_INT2) {
436 data = material_data_int2.at(label);
437 } else {
438 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int2.");
439 }
440 } else if constexpr (std::is_same_v<T, int3>) {
441 if (type == HELIOS_TYPE_INT3) {
442 data = material_data_int3.at(label);
443 } else {
444 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int3.");
445 }
446 } else if constexpr (std::is_same_v<T, int4>) {
447 if (type == HELIOS_TYPE_INT4) {
448 data = material_data_int4.at(label);
449 } else {
450 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int4.");
451 }
452 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
453 if (type == HELIOS_TYPE_STRING) {
454 data = material_data_string.at(label);
455 } else {
456 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type string, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type string.");
457 }
458 }
459 }
460
462
466 bool doesMaterialDataExist(const char *label) const {
467 return material_data_types.find(label) != material_data_types.end();
468 }
469
471
478 helios_runtime_error("ERROR (Material::getMaterialDataType): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
479 }
480 return material_data_types.at(label);
481 }
482
484
488 uint getMaterialDataSize(const char *label) const {
490 helios_runtime_error("ERROR (Material::getMaterialDataSize): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
491 }
493 if (type == HELIOS_TYPE_INT) {
494 return material_data_int.at(label).size();
495 } else if (type == HELIOS_TYPE_UINT) {
496 return material_data_uint.at(label).size();
497 } else if (type == HELIOS_TYPE_FLOAT) {
498 return material_data_float.at(label).size();
499 } else if (type == HELIOS_TYPE_DOUBLE) {
500 return material_data_double.at(label).size();
501 } else if (type == HELIOS_TYPE_VEC2) {
502 return material_data_vec2.at(label).size();
503 } else if (type == HELIOS_TYPE_VEC3) {
504 return material_data_vec3.at(label).size();
505 } else if (type == HELIOS_TYPE_VEC4) {
506 return material_data_vec4.at(label).size();
507 } else if (type == HELIOS_TYPE_INT2) {
508 return material_data_int2.at(label).size();
509 } else if (type == HELIOS_TYPE_INT3) {
510 return material_data_int3.at(label).size();
511 } else if (type == HELIOS_TYPE_INT4) {
512 return material_data_int4.at(label).size();
513 } else if (type == HELIOS_TYPE_STRING) {
514 return material_data_string.at(label).size();
515 }
516 return 0;
517 }
518
520
523 void clearMaterialData(const char *label) {
525 helios_runtime_error("ERROR (Material::clearMaterialData): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
526 }
528 if (type == HELIOS_TYPE_INT) {
530 } else if (type == HELIOS_TYPE_UINT) {
532 } else if (type == HELIOS_TYPE_FLOAT) {
534 } else if (type == HELIOS_TYPE_DOUBLE) {
536 } else if (type == HELIOS_TYPE_VEC2) {
538 } else if (type == HELIOS_TYPE_VEC3) {
540 } else if (type == HELIOS_TYPE_VEC4) {
542 } else if (type == HELIOS_TYPE_INT2) {
544 } else if (type == HELIOS_TYPE_INT3) {
546 } else if (type == HELIOS_TYPE_INT4) {
548 } else if (type == HELIOS_TYPE_STRING) {
550 }
552 }
553
555 std::vector<std::string> listMaterialData() const {
556 std::vector<std::string> data_labels;
557 data_labels.reserve(material_data_types.size());
558 for (const auto &data: material_data_types) {
559 data_labels.push_back(data.first);
560 }
561 return data_labels;
562 }
563 };
564
566 struct GlobalData {
567
569 std::vector<int> global_data_int;
571 std::vector<uint> global_data_uint;
573 std::vector<float> global_data_float;
575 std::vector<double> global_data_double;
577 std::vector<vec2> global_data_vec2;
579 std::vector<vec3> global_data_vec3;
581 std::vector<vec4> global_data_vec4;
583 std::vector<int2> global_data_int2;
585 std::vector<int3> global_data_int3;
587 std::vector<int4> global_data_int4;
589 std::vector<std::string> global_data_string;
591 std::vector<bool> global_data_bool;
592
594 size_t size;
598 uint64_t version = 0;
599 };
600
601 //--------------------- GEOMETRIC PRIMITIVES -----------------------------------//
602
603
604 //---------- COMPOUND OBJECTS ----------------//
605
625
627 public:
629
632 virtual ~CompoundObject() = 0;
633
635 [[nodiscard]] uint getObjectID() const;
636
638 [[nodiscard]] helios::ObjectType getObjectType() const;
639
641 [[nodiscard]] uint getPrimitiveCount() const;
642
644 [[nodiscard]] std::vector<uint> getPrimitiveUUIDs() const;
645
647 [[nodiscard]] bool doesObjectContainPrimitive(uint UUID);
648
650 [[nodiscard]] helios::vec3 getObjectCenter() const;
651
653 [[nodiscard]] float getArea() const;
654
656
659 void setColor(const helios::RGBcolor &color);
660
662
665 void setColor(const helios::RGBAcolor &color);
666
669
672 void useTextureColor();
673
675 [[nodiscard]] bool hasTexture() const;
676
678 [[nodiscard]] std::string getTextureFile() const;
679
681
684 void translate(const helios::vec3 &shift);
685
687
691 void rotate(float rotation_radians, const char *rotation_axis_xyz_string);
692
694
698 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector);
699
701
706 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector);
707
709
712 void scale(const helios::vec3 &scale);
713
715
719
721
725 void scaleAboutPoint(const helios::vec3 &scale, const helios::vec3 &point);
726
728
731 void getTransformationMatrix(float (&T)[16]) const;
732
734
737 void setTransformationMatrix(float (&T)[16]);
738
740
743 void setPrimitiveUUIDs(const std::vector<uint> &UUIDs);
744
746
749 void deleteChildPrimitive(uint UUID);
750
752
755 void deleteChildPrimitive(const std::vector<uint> &UUIDs);
756
758
761 [[nodiscard]] bool arePrimitivesComplete() const;
762
763 //-------- Object Data Methods ---------- //
764
766
771 template<typename T>
772 void setObjectData(const char *label, const T &data) {
773
774 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
775 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
776 "CompoundObject::setObjectData() was called with an unsupported type.");
777
778 if constexpr (std::is_same_v<T, int>) {
779 object_data_int[label] = {data};
780 object_data_types[label] = HELIOS_TYPE_INT;
781 } else if constexpr (std::is_same_v<T, uint>) {
782 object_data_uint[label] = {data};
783 object_data_types[label] = HELIOS_TYPE_UINT;
784 } else if constexpr (std::is_same_v<T, float>) {
785 object_data_float[label] = {data};
786 object_data_types[label] = HELIOS_TYPE_FLOAT;
787 } else if constexpr (std::is_same_v<T, double>) {
788 object_data_double[label] = {data};
789 object_data_types[label] = HELIOS_TYPE_DOUBLE;
790 } else if constexpr (std::is_same_v<T, vec2>) {
791 object_data_vec2[label] = {data};
792 object_data_types[label] = HELIOS_TYPE_VEC2;
793 } else if constexpr (std::is_same_v<T, vec3>) {
794 object_data_vec3[label] = {data};
795 object_data_types[label] = HELIOS_TYPE_VEC3;
796 } else if constexpr (std::is_same_v<T, vec4>) {
797 object_data_vec4[label] = {data};
798 object_data_types[label] = HELIOS_TYPE_VEC4;
799 } else if constexpr (std::is_same_v<T, int2>) {
800 object_data_int2[label] = {data};
801 object_data_types[label] = HELIOS_TYPE_INT2;
802 } else if constexpr (std::is_same_v<T, int3>) {
803 object_data_int3[label] = {data};
804 object_data_types[label] = HELIOS_TYPE_INT3;
805 } else if constexpr (std::is_same_v<T, int4>) {
806 object_data_int4[label] = {data};
807 object_data_types[label] = HELIOS_TYPE_INT4;
808 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
809 object_data_string[label] = {data};
810 object_data_types[label] = HELIOS_TYPE_STRING;
811 }
812 }
813
815
820 template<typename T>
821 void setObjectData(const char *label, const std::vector<T> &data) {
822
823 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
824 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
825 "CompoundObject::setObjectData() was called with an unsupported type.");
826
827 if constexpr (std::is_same_v<T, int>) {
828 object_data_int[label] = data;
829 object_data_types[label] = HELIOS_TYPE_INT;
830 } else if constexpr (std::is_same_v<T, uint>) {
831 object_data_uint[label] = data;
832 object_data_types[label] = HELIOS_TYPE_UINT;
833 } else if constexpr (std::is_same_v<T, float>) {
834 object_data_float[label] = data;
835 object_data_types[label] = HELIOS_TYPE_FLOAT;
836 } else if constexpr (std::is_same_v<T, double>) {
837 object_data_double[label] = data;
838 object_data_types[label] = HELIOS_TYPE_DOUBLE;
839 } else if constexpr (std::is_same_v<T, vec2>) {
840 object_data_vec2[label] = data;
841 object_data_types[label] = HELIOS_TYPE_VEC2;
842 } else if constexpr (std::is_same_v<T, vec3>) {
843 object_data_vec3[label] = data;
844 object_data_types[label] = HELIOS_TYPE_VEC3;
845 } else if constexpr (std::is_same_v<T, vec4>) {
846 object_data_vec4[label] = data;
847 object_data_types[label] = HELIOS_TYPE_VEC4;
848 } else if constexpr (std::is_same_v<T, int2>) {
849 object_data_int2[label] = data;
850 object_data_types[label] = HELIOS_TYPE_INT2;
851 } else if constexpr (std::is_same_v<T, int3>) {
852 object_data_int3[label] = data;
853 object_data_types[label] = HELIOS_TYPE_INT3;
854 } else if constexpr (std::is_same_v<T, int4>) {
855 object_data_int4[label] = data;
856 object_data_types[label] = HELIOS_TYPE_INT4;
857 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
858 object_data_string[label] = data;
859 object_data_types[label] = HELIOS_TYPE_STRING;
860 }
861 }
862
864
868 template<typename T>
869 void getObjectData(const char *label, T &data) const {
870#ifdef HELIOS_DEBUG
871 if (!doesObjectDataExist(label)) {
872 helios_runtime_error("ERROR (CompoundObject::getObjectData): Object data " + std::string(label) + " does not exist for primitive " + std::to_string(OID));
873 }
874#endif
875
876 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
877 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
878 "CompoundObject::getObjectData() was called with an unsupported type.");
879
880 HeliosDataType type = object_data_types.at(label);
881
882 if constexpr (std::is_same_v<T, int>) {
883 if (type == HELIOS_TYPE_INT) {
884 data = object_data_int.at(label).front();
885 } else {
886 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int.");
887 }
888 } else if constexpr (std::is_same_v<T, uint>) {
889 if (type == HELIOS_TYPE_UINT) {
890 data = object_data_uint.at(label).front();
891 } else {
892 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type uint, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type uint.");
893 }
894 } else if constexpr (std::is_same_v<T, float>) {
895 if (type == HELIOS_TYPE_FLOAT) {
896 data = object_data_float.at(label).front();
897 } else {
898 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type float, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type float.");
899 }
900 } else if constexpr (std::is_same_v<T, double>) {
901 if (type == HELIOS_TYPE_DOUBLE) {
902 data = object_data_double.at(label).front();
903 } else {
904 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type double, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type double.");
905 }
906 } else if constexpr (std::is_same_v<T, vec2>) {
907 if (type == HELIOS_TYPE_VEC2) {
908 data = object_data_vec2.at(label).front();
909 } else {
910 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec2.");
911 }
912 } else if constexpr (std::is_same_v<T, vec3>) {
913 if (type == HELIOS_TYPE_VEC3) {
914 data = object_data_vec3.at(label).front();
915 } else {
916 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec3.");
917 }
918 } else if constexpr (std::is_same_v<T, vec4>) {
919 if (type == HELIOS_TYPE_VEC4) {
920 data = object_data_vec4.at(label).front();
921 } else {
922 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec4.");
923 }
924 } else if constexpr (std::is_same_v<T, int2>) {
925 if (type == HELIOS_TYPE_INT2) {
926 data = object_data_int2.at(label).front();
927 } else {
928 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int2.");
929 }
930 } else if constexpr (std::is_same_v<T, int3>) {
931 if (type == HELIOS_TYPE_INT3) {
932 data = object_data_int3.at(label).front();
933 } else {
934 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int3.");
935 }
936 } else if constexpr (std::is_same_v<T, int4>) {
937 if (type == HELIOS_TYPE_INT4) {
938 data = object_data_int4.at(label).front();
939 } else {
940 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int4.");
941 }
942 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
943 if (type == HELIOS_TYPE_STRING) {
944 data = object_data_string.at(label).front();
945 } else {
946 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type string, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type string.");
947 }
948 }
949 }
950
952
957 template<typename T>
958 void getObjectData(const char *label, std::vector<T> &data) const {
959#ifdef HELIOS_DEBUG
960 if (!doesObjectDataExist(label)) {
961 helios_runtime_error("ERROR (CompoundObject::getObjectData): Object data " + std::string(label) + " does not exist for object " + std::to_string(OID));
962 }
963#endif
964
965 HeliosDataType type = object_data_types.at(label);
966
967 if constexpr (std::is_same_v<T, int>) {
968 if (type == HELIOS_TYPE_INT) {
969 data = object_data_int.at(label);
970 } else {
971 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int.");
972 }
973 } else if constexpr (std::is_same_v<T, uint>) {
974 if (type == HELIOS_TYPE_UINT) {
975 data = object_data_uint.at(label);
976 } else {
977 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type uint, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type uint.");
978 }
979 } else if constexpr (std::is_same_v<T, float>) {
980 if (type == HELIOS_TYPE_FLOAT) {
981 data = object_data_float.at(label);
982 } else {
983 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type float, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type float.");
984 }
985 } else if constexpr (std::is_same_v<T, double>) {
986 if (type == HELIOS_TYPE_DOUBLE) {
987 data = object_data_double.at(label);
988 } else {
989 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type double, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type double.");
990 }
991 } else if constexpr (std::is_same_v<T, vec2>) {
992 if (type == HELIOS_TYPE_VEC2) {
993 data = object_data_vec2.at(label);
994 } else {
995 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec2.");
996 }
997 } else if constexpr (std::is_same_v<T, vec3>) {
998 if (type == HELIOS_TYPE_VEC3) {
999 data = object_data_vec3.at(label);
1000 } else {
1001 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec3.");
1002 }
1003 } else if constexpr (std::is_same_v<T, vec4>) {
1004 if (type == HELIOS_TYPE_VEC4) {
1005 data = object_data_vec4.at(label);
1006 } else {
1007 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec4.");
1008 }
1009 } else if constexpr (std::is_same_v<T, int2>) {
1010 if (type == HELIOS_TYPE_INT2) {
1011 data = object_data_int2.at(label);
1012 } else {
1013 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int2.");
1014 }
1015 } else if constexpr (std::is_same_v<T, int3>) {
1016 if (type == HELIOS_TYPE_INT3) {
1017 data = object_data_int3.at(label);
1018 } else {
1019 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int3.");
1020 }
1021 } else if constexpr (std::is_same_v<T, int4>) {
1022 if (type == HELIOS_TYPE_INT4) {
1023 data = object_data_int4.at(label);
1024 } else {
1025 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int4.");
1026 }
1027 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
1028 if (type == HELIOS_TYPE_STRING) {
1029 data = object_data_string.at(label);
1030 } else {
1031 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type string, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type string.");
1032 }
1033 }
1034 }
1035
1037
1042 HeliosDataType getObjectDataType(const char *label) const;
1043
1045
1049 uint getObjectDataSize(const char *label) const;
1050
1052
1056 bool doesObjectDataExist(const char *label) const;
1057
1059
1062 void clearObjectData(const char *label);
1063
1065 [[nodiscard]] std::vector<std::string> listObjectData() const;
1066
1067 protected:
1069 uint OID;
1070
1072 helios::ObjectType type;
1073
1075 std::vector<uint> UUIDs;
1076
1078 helios::Context *context;
1079
1081 std::string texturefile;
1082
1084 float transform[16];
1085
1087 helios::vec3 object_origin;
1088
1090 bool primitivesarecomplete = true;
1091
1092 std::map<std::string, HeliosDataType> object_data_types;
1093 std::map<std::string, std::vector<int>> object_data_int;
1094 std::map<std::string, std::vector<uint>> object_data_uint;
1095 std::map<std::string, std::vector<float>> object_data_float;
1096 std::map<std::string, std::vector<double>> object_data_double;
1097 std::map<std::string, std::vector<vec2>> object_data_vec2;
1098 std::map<std::string, std::vector<vec3>> object_data_vec3;
1099 std::map<std::string, std::vector<vec4>> object_data_vec4;
1100 std::map<std::string, std::vector<int2>> object_data_int2;
1101 std::map<std::string, std::vector<int3>> object_data_int3;
1102 std::map<std::string, std::vector<int4>> object_data_int4;
1103 std::map<std::string, std::vector<std::string>> object_data_string;
1104 std::map<std::string, std::vector<bool>> object_data_bool;
1105
1106 bool ishidden = false;
1107
1108 friend class Context;
1109 };
1110
1112 class Tile final : public CompoundObject {
1113 public:
1115 ~Tile() override = default;
1116
1118 [[nodiscard]] helios::vec2 getSize() const;
1119
1121 [[nodiscard]] helios::vec3 getCenter() const;
1122
1124 [[nodiscard]] helios::int2 getSubdivisionCount() const;
1125
1127
1131 void setSubdivisionCount(const helios::int2 &subdiv);
1132
1134 [[nodiscard]] std::vector<helios::vec3> getVertices() const;
1135
1137 [[nodiscard]] helios::vec3 getNormal() const;
1138
1140 [[nodiscard]] std::vector<helios::vec2> getTextureUV() const;
1141
1142 protected:
1144
1147 Tile(uint a_OID, const std::vector<uint> &a_UUIDs, const int2 &a_subdiv, const char *a_texturefile, helios::Context *a_context);
1148
1149 helios::int2 subdiv;
1150
1151 friend class CompoundObject;
1152 friend class Context;
1153 };
1154
1156 class Sphere final : public CompoundObject {
1157 public:
1159 ~Sphere() override = default;
1160
1162 [[nodiscard]] helios::vec3 getRadius() const;
1163
1165 [[nodiscard]] helios::vec3 getCenter() const;
1166
1168 [[nodiscard]] uint getSubdivisionCount() const;
1169
1171
1174 void setSubdivisionCount(uint subdiv);
1175
1177 [[nodiscard]] float getVolume() const;
1178
1179 protected:
1181
1184 Sphere(uint a_OID, const std::vector<uint> &a_UUIDs, uint a_subdiv, const char *a_texturefile, helios::Context *a_context);
1185
1186 uint subdiv;
1187
1188 friend class CompoundObject;
1189 friend class Context;
1190 };
1191
1193 class Tube final : public CompoundObject {
1194 public:
1196 ~Tube() override = default;
1197
1199 [[nodiscard]] std::vector<helios::vec3> getNodes() const;
1200
1202 [[nodiscard]] uint getNodeCount() const;
1203
1205 [[nodiscard]] std::vector<float> getNodeRadii() const;
1206
1208 [[nodiscard]] std::vector<helios::RGBcolor> getNodeColors() const;
1209
1211 [[nodiscard]] std::vector<std::vector<helios::vec3>> getTriangleVertices() const;
1212
1214 [[nodiscard]] uint getSubdivisionCount() const;
1215
1217 [[nodiscard]] float getLength() const;
1218
1220 [[nodiscard]] float getVolume() const;
1221
1223
1226 [[nodiscard]] float getSegmentVolume(uint segment_index) const;
1227
1229
1234 void appendTubeSegment(const helios::vec3 &node_position, float node_radius, const helios::RGBcolor &node_color);
1235
1237
1243 void appendTubeSegment(const helios::vec3 &node_position, float node_radius, const char *texturefile, const helios::vec2 &textureuv_ufrac);
1244
1246
1249 void scaleTubeGirth(float S);
1250
1252
1255 void setTubeRadii(const std::vector<float> &node_radii);
1256
1258
1261 void scaleTubeLength(float S);
1262
1264
1267 void setTubeNodes(const std::vector<helios::vec3> &node_xyz);
1268
1270
1273 void pruneTubeNodes(uint node_index);
1274
1275 protected:
1277
1280 Tube(uint a_OID, const std::vector<uint> &a_UUIDs, const std::vector<vec3> &a_nodes, const std::vector<float> &a_radius, const std::vector<helios::RGBcolor> &a_colors, const std::vector<std::vector<helios::vec3>> &a_triangle_vertices,
1281 uint a_subdiv, const char *a_texturefile, helios::Context *a_context);
1282
1283 std::vector<helios::vec3> nodes;
1284
1285 std::vector<std::vector<helios::vec3>> triangle_vertices; // first index is the tube segment ring, second index is vertex within segment ring, third index is the vertex within triangle
1286
1287 std::vector<float> radius;
1288
1289 std::vector<helios::RGBcolor> colors;
1290
1291 uint subdiv;
1292
1293 void updateTriangleVertices() const;
1294
1295 void recomputeCrossSections();
1296
1297 friend class CompoundObject;
1298 friend class Context;
1299 };
1300
1302 class Box final : public CompoundObject {
1303 public:
1305 ~Box() override = default;
1306
1308 [[nodiscard]] helios::vec3 getSize() const;
1309
1311 [[nodiscard]] helios::vec3 getCenter() const;
1312
1314 [[nodiscard]] helios::int3 getSubdivisionCount() const;
1315
1317
1320 void setSubdivisionCount(const helios::int3 &subdiv);
1321
1323 [[nodiscard]] float getVolume() const;
1324
1325 protected:
1327
1330 Box(uint a_OID, const std::vector<uint> &a_UUIDs, const int3 &a_subdiv, const char *a_texturefile, helios::Context *a_context);
1331
1332 helios::int3 subdiv;
1333
1334 friend class CompoundObject;
1335 friend class Context;
1336 };
1337
1339 class Disk final : public CompoundObject {
1340 public:
1342 ~Disk() override = default;
1343
1345 [[nodiscard]] helios::vec2 getSize() const;
1346
1348 [[nodiscard]] helios::vec3 getCenter() const;
1349
1351 [[nodiscard]] helios::int2 getSubdivisionCount() const;
1352
1354
1357 void setSubdivisionCount(const helios::int2 &subdiv);
1358
1359 protected:
1361
1364 Disk(uint a_OID, const std::vector<uint> &a_UUIDs, int2 a_subdiv, const char *a_texturefile, helios::Context *a_context);
1365
1366 int2 subdiv;
1367
1368 friend class CompoundObject;
1369 friend class Context;
1370 };
1371
1373 class Polymesh final : public CompoundObject {
1374 public:
1376 ~Polymesh() override = default;
1377
1379 [[nodiscard]] float getVolume() const;
1380
1381 protected:
1383
1386 Polymesh(uint a_OID, const std::vector<uint> &a_UUIDs, const char *a_texturefile, helios::Context *a_context);
1387
1388 friend class CompoundObject;
1389 friend class Context;
1390 };
1391
1393 class Cone final : public CompoundObject {
1394 public:
1396 ~Cone() override = default;
1397
1399
1402 [[nodiscard]] std::vector<helios::vec3> getNodeCoordinates() const;
1403
1405
1409 [[nodiscard]] helios::vec3 getNodeCoordinate(int node_index) const;
1410
1412
1415 [[nodiscard]] std::vector<float> getNodeRadii() const;
1416
1418
1422 [[nodiscard]] float getNodeRadius(int node_index) const;
1423
1425 [[nodiscard]] uint getSubdivisionCount() const;
1426
1428
1431 void setSubdivisionCount(uint subdiv);
1432
1434 [[nodiscard]] helios::vec3 getAxisUnitVector() const;
1435
1437 [[nodiscard]] float getLength() const;
1438
1440
1443 void scaleLength(float S);
1444
1446
1449 void scaleGirth(float S);
1450
1452 [[nodiscard]] float getVolume() const;
1453
1454 protected:
1456
1459 Cone(uint a_OID, const std::vector<uint> &a_UUIDs, const vec3 &a_node0, const vec3 &a_node1, float a_radius0, float a_radius1, uint a_subdiv, const char *a_texturefile, helios::Context *a_context);
1460
1461 std::vector<helios::vec3> nodes;
1462 std::vector<float> radii;
1463
1464 uint subdiv;
1465
1466 friend class CompoundObject;
1467 friend class Context;
1468 };
1469
1470
1472
1476 class Primitive {
1477 public:
1479
1482 virtual ~Primitive() = 0;
1483
1485
1488 [[nodiscard]] uint getUUID() const;
1489
1491
1494 [[nodiscard]] PrimitiveType getType() const;
1495
1497
1500 void setParentObjectID(uint objID);
1501
1503 [[nodiscard]] uint getParentObjectID() const;
1504
1506 [[nodiscard]] virtual float getArea() const = 0;
1507
1509 [[nodiscard]] virtual helios::vec3 getNormal() const = 0;
1510
1512
1515 void getTransformationMatrix(float (&T)[16]) const;
1516
1518
1521 void setTransformationMatrix(float (&T)[16]);
1522
1524 [[nodiscard]] virtual std::vector<helios::vec3> getVertices() const = 0;
1525
1527 [[nodiscard]] virtual helios::vec3 getCenter() const = 0;
1528
1530 [[nodiscard]] helios::RGBcolor getColor() const;
1531
1533 [[nodiscard]] helios::RGBcolor getColorRGB() const;
1534
1536 [[nodiscard]] helios::RGBAcolor getColorRGBA() const;
1537
1539
1542 void setColor(const helios::RGBcolor &color);
1543
1545
1548 void setColor(const helios::RGBAcolor &color);
1549
1551 [[nodiscard]] bool hasTexture() const;
1552
1554 [[nodiscard]] std::string getTextureFile() const;
1555
1557
1560 void setTextureFile(const char *texture);
1561
1563
1566 [[nodiscard]] std::vector<vec2> getTextureUV();
1567
1568
1570
1573 void setTextureUV(const std::vector<vec2> &uv);
1574
1576 void overrideTextureColor();
1577
1579 void useTextureColor();
1580
1582 [[nodiscard]] bool isTextureColorOverridden() const;
1583
1585
1588 [[nodiscard]] float getSolidFraction() const;
1589
1591
1594 void setSolidFraction(float solidFraction);
1595
1597
1600 void applyTransform(float (&T)[16]);
1601
1603
1606 void translate(const helios::vec3 &shift);
1607
1609
1613 virtual void rotate(float rotation_radians, const char *rotation_axis_xyz_string) = 0;
1614
1616
1620 virtual void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) = 0;
1621
1623
1628 virtual void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) = 0;
1629
1631
1634 void scale(const helios::vec3 &S);
1635
1637
1641 void scale(const helios::vec3 &S, const helios::vec3 &point);
1642
1643 //-------- Primitive Data Methods ---------- //
1644
1646
1651 template<typename T>
1652 void setPrimitiveData(const char *label, const T &data) {
1653 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
1654 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
1655 "Primitive::setPrimitiveData() was called with an unsupported type.");
1656
1657 if constexpr (std::is_same_v<T, int>) {
1658 primitive_data_int[label] = {data};
1659 primitive_data_types[label] = HELIOS_TYPE_INT;
1660 } else if constexpr (std::is_same_v<T, uint>) {
1661 primitive_data_uint[label] = {data};
1662 primitive_data_types[label] = HELIOS_TYPE_UINT;
1663 } else if constexpr (std::is_same_v<T, float>) {
1664 primitive_data_float[label] = {data};
1665 primitive_data_types[label] = HELIOS_TYPE_FLOAT;
1666 } else if constexpr (std::is_same_v<T, double>) {
1667 primitive_data_double[label] = {data};
1668 primitive_data_types[label] = HELIOS_TYPE_DOUBLE;
1669 } else if constexpr (std::is_same_v<T, vec2>) {
1670 primitive_data_vec2[label] = {data};
1671 primitive_data_types[label] = HELIOS_TYPE_VEC2;
1672 } else if constexpr (std::is_same_v<T, vec3>) {
1673 primitive_data_vec3[label] = {data};
1674 primitive_data_types[label] = HELIOS_TYPE_VEC3;
1675 } else if constexpr (std::is_same_v<T, vec4>) {
1676 primitive_data_vec4[label] = {data};
1677 primitive_data_types[label] = HELIOS_TYPE_VEC4;
1678 } else if constexpr (std::is_same_v<T, int2>) {
1679 primitive_data_int2[label] = {data};
1680 primitive_data_types[label] = HELIOS_TYPE_INT2;
1681 } else if constexpr (std::is_same_v<T, int3>) {
1682 primitive_data_int3[label] = {data};
1683 primitive_data_types[label] = HELIOS_TYPE_INT3;
1684 } else if constexpr (std::is_same_v<T, int4>) {
1685 primitive_data_int4[label] = {data};
1686 primitive_data_types[label] = HELIOS_TYPE_INT4;
1687 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
1688 primitive_data_string[label] = {data};
1689 primitive_data_types[label] = HELIOS_TYPE_STRING;
1690 }
1691 dirty_flag = true;
1692 }
1693
1695
1700 template<typename T>
1701 void setPrimitiveData(const char *label, const std::vector<T> &data) {
1702 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
1703 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
1704 "Primitive::setPrimitiveData() was called with an unsupported type.");
1705
1706 if constexpr (std::is_same_v<T, int>) {
1707 primitive_data_int[label] = data;
1708 primitive_data_types[label] = HELIOS_TYPE_INT;
1709 } else if constexpr (std::is_same_v<T, uint>) {
1710 primitive_data_uint[label] = data;
1711 primitive_data_types[label] = HELIOS_TYPE_UINT;
1712 } else if constexpr (std::is_same_v<T, float>) {
1713 primitive_data_float[label] = data;
1714 primitive_data_types[label] = HELIOS_TYPE_FLOAT;
1715 } else if constexpr (std::is_same_v<T, double>) {
1716 primitive_data_double[label] = data;
1717 primitive_data_types[label] = HELIOS_TYPE_DOUBLE;
1718 } else if constexpr (std::is_same_v<T, vec2>) {
1719 primitive_data_vec2[label] = data;
1720 primitive_data_types[label] = HELIOS_TYPE_VEC2;
1721 } else if constexpr (std::is_same_v<T, vec3>) {
1722 primitive_data_vec3[label] = data;
1723 primitive_data_types[label] = HELIOS_TYPE_VEC3;
1724 } else if constexpr (std::is_same_v<T, vec4>) {
1725 primitive_data_vec4[label] = data;
1726 primitive_data_types[label] = HELIOS_TYPE_VEC4;
1727 } else if constexpr (std::is_same_v<T, int2>) {
1728 primitive_data_int2[label] = data;
1729 primitive_data_types[label] = HELIOS_TYPE_INT2;
1730 } else if constexpr (std::is_same_v<T, int3>) {
1731 primitive_data_int3[label] = data;
1732 primitive_data_types[label] = HELIOS_TYPE_INT3;
1733 } else if constexpr (std::is_same_v<T, int4>) {
1734 primitive_data_int4[label] = data;
1735 primitive_data_types[label] = HELIOS_TYPE_INT4;
1736 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
1737 primitive_data_string[label] = data;
1738 primitive_data_types[label] = HELIOS_TYPE_STRING;
1739 }
1740 dirty_flag = true;
1741 }
1742
1744
1749 template<typename T>
1750 void getPrimitiveData(const char *label, T &data) const {
1751#ifdef HELIOS_DEBUG
1752 if (!doesPrimitiveDataExist(label)) {
1753 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
1754 }
1755#endif
1756 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
1757 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
1758 "Primitive::getPrimitiveData() was called with an unsupported type.");
1759
1760 HeliosDataType type = primitive_data_types.at(label);
1761
1762 if constexpr (std::is_same_v<T, int>) {
1763 if (type == HELIOS_TYPE_INT) {
1764 data = primitive_data_int.at(label).front();
1765 } else {
1766 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int.");
1767 }
1768 } else if constexpr (std::is_same_v<T, uint>) {
1769 if (type == HELIOS_TYPE_UINT) {
1770 data = primitive_data_uint.at(label).front();
1771 } else {
1772 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type uint, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type uint.");
1773 }
1774 } else if constexpr (std::is_same_v<T, float>) {
1775 if (type == HELIOS_TYPE_FLOAT) {
1776 data = primitive_data_float.at(label).front();
1777 } else {
1778 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type float, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type float.");
1779 }
1780 } else if constexpr (std::is_same_v<T, double>) {
1781 if (type == HELIOS_TYPE_DOUBLE) {
1782 data = primitive_data_double.at(label).front();
1783 } else {
1784 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type double, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type double.");
1785 }
1786 } else if constexpr (std::is_same_v<T, vec2>) {
1787 if (type == HELIOS_TYPE_VEC2) {
1788 data = primitive_data_vec2.at(label).front();
1789 } else {
1790 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type vec2, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type vec2.");
1791 }
1792 } else if constexpr (std::is_same_v<T, vec3>) {
1793 if (type == HELIOS_TYPE_VEC3) {
1794 data = primitive_data_vec3.at(label).front();
1795 } else {
1796 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type vec3, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type vec3.");
1797 }
1798 } else if constexpr (std::is_same_v<T, vec4>) {
1799 if (type == HELIOS_TYPE_VEC4) {
1800 data = primitive_data_vec4.at(label).front();
1801 } else {
1802 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type vec4, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type vec4.");
1803 }
1804 } else if constexpr (std::is_same_v<T, int2>) {
1805 if (type == HELIOS_TYPE_INT2) {
1806 data = primitive_data_int2.at(label).front();
1807 } else {
1808 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int2, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int2.");
1809 }
1810 } else if constexpr (std::is_same_v<T, int3>) {
1811 if (type == HELIOS_TYPE_INT3) {
1812 data = primitive_data_int3.at(label).front();
1813 } else {
1814 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int3, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int3.");
1815 }
1816 } else if constexpr (std::is_same_v<T, int4>) {
1817 if (type == HELIOS_TYPE_INT4) {
1818 data = primitive_data_int4.at(label).front();
1819 } else {
1820 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int4, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int4.");
1821 }
1822 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
1823 if (type == HELIOS_TYPE_STRING) {
1824 data = primitive_data_string.at(label).front();
1825 } else {
1826 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type string, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type string.");
1827 }
1828 }
1829 }
1830
1832
1837 template<typename T>
1838 void getPrimitiveData(const char *label, std::vector<T> &data) const {
1839#ifdef HELIOS_DEBUG
1840 if (!doesPrimitiveDataExist(label)) {
1841 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
1842 }
1843#endif
1844 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
1845 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
1846 "Primitive::getPrimitiveData() was called with an unsupported type.");
1847
1848 HeliosDataType type = primitive_data_types.at(label);
1849
1850 if constexpr (std::is_same_v<T, int>) {
1851 if (type == HELIOS_TYPE_INT) {
1852 data = primitive_data_int.at(label);
1853 } else {
1854 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int.");
1855 }
1856 } else if constexpr (std::is_same_v<T, uint>) {
1857 if (type == HELIOS_TYPE_UINT) {
1858 data = primitive_data_uint.at(label);
1859 } else {
1860 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type uint, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type uint.");
1861 }
1862 } else if constexpr (std::is_same_v<T, float>) {
1863 if (type == HELIOS_TYPE_FLOAT) {
1864 data = primitive_data_float.at(label);
1865 } else {
1866 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type float, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type float.");
1867 }
1868 } else if constexpr (std::is_same_v<T, double>) {
1869 if (type == HELIOS_TYPE_DOUBLE) {
1870 data = primitive_data_double.at(label);
1871 } else {
1872 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type double, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type double.");
1873 }
1874 } else if constexpr (std::is_same_v<T, vec2>) {
1875 if (type == HELIOS_TYPE_VEC2) {
1876 data = primitive_data_vec2.at(label);
1877 } else {
1878 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type vec2, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type vec2.");
1879 }
1880 } else if constexpr (std::is_same_v<T, vec3>) {
1881 if (type == HELIOS_TYPE_VEC3) {
1882 data = primitive_data_vec3.at(label);
1883 } else {
1884 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type vec3, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type vec3.");
1885 }
1886 } else if constexpr (std::is_same_v<T, vec4>) {
1887 if (type == HELIOS_TYPE_VEC4) {
1888 data = primitive_data_vec4.at(label);
1889 } else {
1890 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type vec4, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type vec4.");
1891 }
1892 } else if constexpr (std::is_same_v<T, int2>) {
1893 if (type == HELIOS_TYPE_INT2) {
1894 data = primitive_data_int2.at(label);
1895 } else {
1896 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int2, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int2.");
1897 }
1898 } else if constexpr (std::is_same_v<T, int3>) {
1899 if (type == HELIOS_TYPE_INT3) {
1900 data = primitive_data_int3.at(label);
1901 } else {
1902 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int3, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int3.");
1903 }
1904 } else if constexpr (std::is_same_v<T, int4>) {
1905 if (type == HELIOS_TYPE_INT4) {
1906 data = primitive_data_int4.at(label);
1907 } else {
1908 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type int4, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type int4.");
1909 }
1910 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
1911 if (type == HELIOS_TYPE_STRING) {
1912 data = primitive_data_string.at(label);
1913 } else {
1914 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Attempted to get data for type string, but data " + std::string(label) + " for primitive " + std::to_string(UUID) + " does not have type string.");
1915 }
1916 }
1917 }
1918
1920
1925 HeliosDataType getPrimitiveDataType(const char *label) const;
1926
1928
1932 uint getPrimitiveDataSize(const char *label) const;
1933
1935
1939 bool doesPrimitiveDataExist(const char *label) const;
1940
1942
1945 void clearPrimitiveData(const char *label);
1946
1948 [[nodiscard]] std::vector<std::string> listPrimitiveData() const;
1949
1950 protected:
1952 uint UUID;
1953
1955 PrimitiveType prim_type;
1956
1958 uint parent_object_ID;
1959
1961
1962 uint materialID;
1963
1965 Context *context_ptr;
1966
1968 float transform[16];
1969
1971 std::vector<vec2> uv;
1972
1974 float solid_fraction;
1975
1977 bool dirty_flag;
1978
1979 std::map<std::string, HeliosDataType> primitive_data_types;
1980 std::map<std::string, std::vector<int>> primitive_data_int;
1981 std::map<std::string, std::vector<uint>> primitive_data_uint;
1982 std::map<std::string, std::vector<float>> primitive_data_float;
1983 std::map<std::string, std::vector<double>> primitive_data_double;
1984 std::map<std::string, std::vector<vec2>> primitive_data_vec2;
1985 std::map<std::string, std::vector<vec3>> primitive_data_vec3;
1986 std::map<std::string, std::vector<vec4>> primitive_data_vec4;
1987 std::map<std::string, std::vector<int2>> primitive_data_int2;
1988 std::map<std::string, std::vector<int3>> primitive_data_int3;
1989 std::map<std::string, std::vector<int4>> primitive_data_int4;
1990 std::map<std::string, std::vector<std::string>> primitive_data_string;
1991 std::map<std::string, std::vector<bool>> primitive_data_bool;
1992
1993 bool ishidden = false;
1994
1995 friend class Context;
1996 };
1997
1998
2000
2005 class Patch : public Primitive {
2006 public:
2008 ~Patch() override = default;
2009
2011
2014 [[nodiscard]] float getArea() const override;
2015
2017
2020 [[nodiscard]] helios::vec3 getNormal() const override;
2021
2023
2026 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
2027
2029
2032 [[nodiscard]] helios::vec2 getSize() const;
2033
2035
2038 [[nodiscard]] helios::vec3 getCenter() const override;
2039
2041
2045 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
2046
2048
2052 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
2053
2055
2060 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
2061
2062 protected:
2064
2070 Patch(const helios::RGBAcolor &color, uint parent_objID, uint UUID);
2071
2073
2080 Patch(const char *texturefile, float solid_fraction, uint parent_objID, uint UUID);
2081
2083
2091 Patch(const char *texturefile, const std::vector<helios::vec2> &uv, std::map<std::string, Texture> &textures, uint parent_objID, uint UUID);
2092
2093
2094 friend class Primitive;
2095 friend class Context;
2096 };
2097
2099
2104 class Triangle : public Primitive {
2105 public:
2107 ~Triangle() override = default;
2108
2110
2113 [[nodiscard]] float getArea() const override;
2114
2116
2119 [[nodiscard]] helios::vec3 getNormal() const override;
2120
2122
2125 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
2126
2128
2132 [[nodiscard]] helios::vec3 getVertex(int vertex_index) const;
2133
2135
2138 [[nodiscard]] helios::vec3 getCenter() const override;
2139
2141
2145 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
2146
2148
2152 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
2153
2155
2160 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
2161
2163
2168 void setVertices(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2169
2170 private:
2172
2181 Triangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBAcolor &color, uint parent_objID, uint UUID);
2182
2184
2195 Triangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const char *texturefile, const std::vector<helios::vec2> &uv, float solid_fraction, uint parent_objID, uint UUID);
2196
2198
2209 Triangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const char *texturefile, const std::vector<helios::vec2> &uv, std::map<std::string, Texture> &textures, uint parent_objID, uint UUID);
2210
2211 void makeTransformationMatrix(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2212
2213 bool edgeFunction(const helios::vec2 &a, const helios::vec2 &b, const helios::vec2 &c);
2214
2215 friend class Primitive;
2216 friend class Context;
2217 };
2218
2220
2223 class Voxel : public Primitive {
2224 public:
2226 ~Voxel() override = default;
2227
2229
2232 [[nodiscard]] float getArea() const override;
2233
2235 [[nodiscard]] helios::vec3 getNormal() const override;
2236
2238
2241 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
2242
2244
2247 float getVolume();
2248
2250
2253 [[nodiscard]] helios::vec3 getCenter() const override;
2254
2256
2259 [[nodiscard]] helios::vec3 getSize() const;
2260
2262
2266 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
2267
2269
2273 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
2274
2275
2277
2282 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
2283
2284 protected:
2286
2292 Voxel(const helios::RGBAcolor &color, uint parent_objID, uint UUID);
2293
2294 friend class Primitive;
2295 friend class Context;
2296 };
2297
2300 public:
2302
2307 static int parse_data_float(const pugi::xml_node &node_data, std::vector<float> &data);
2308
2310
2315 static int parse_data_double(const pugi::xml_node &node_data, std::vector<double> &data);
2316
2318
2323 static int parse_data_int(const pugi::xml_node &node_data, std::vector<int> &data);
2324
2326
2331 static int parse_data_uint(const pugi::xml_node &node_data, std::vector<uint> &data);
2332
2334
2339 static int parse_data_string(const pugi::xml_node &node_data, std::vector<std::string> &data);
2340
2342
2347 static int parse_data_vec2(const pugi::xml_node &node_data, std::vector<vec2> &data);
2348
2350
2355 static int parse_data_vec3(const pugi::xml_node &node_data, std::vector<vec3> &data);
2356
2358
2363 static int parse_data_vec4(const pugi::xml_node &node_data, std::vector<vec4> &data);
2364
2366
2371 static int parse_data_int2(const pugi::xml_node &node_data, std::vector<int2> &data);
2372
2374
2379 static int parse_data_int3(const pugi::xml_node &node_data, std::vector<int3> &data);
2380
2382
2387 static int parse_data_int4(const pugi::xml_node &node_data, std::vector<int4> &data);
2388
2390
2395 static int parse_objID(const pugi::xml_node &node_data, uint &objID);
2396
2398
2403 static int parse_transform(const pugi::xml_node &node_data, float (&transform)[16]);
2404
2406
2411 static int parse_texture(const pugi::xml_node &node_data, std::string &texture);
2412
2414
2419 static int parse_textureUV(const pugi::xml_node &node_data, std::vector<vec2> &uvs);
2420
2422
2427 static int parse_solid_fraction(const pugi::xml_node &node_data, float &solid_fraction);
2428
2430
2435 static int parse_vertices(const pugi::xml_node &node_data, std::vector<float> &vertices);
2436
2438
2443 static int parse_subdivisions(const pugi::xml_node &node_data, uint &subdivisions);
2444
2446
2451 static int parse_subdivisions(const pugi::xml_node &node_data, int2 &subdivisions);
2452
2454
2459 static int parse_subdivisions(const pugi::xml_node &node_data, int3 &subdivisions);
2460
2462
2467 static int parse_nodes(const pugi::xml_node &node_data, std::vector<vec3> &nodes);
2468
2470
2475 static int parse_radius(const pugi::xml_node &node_data, std::vector<float> &radius);
2476 };
2477
2479
2482 class Context {
2483 friend class Primitive; // Allow Primitive methods to access private material data
2484
2485 private:
2486 //---------- PRIMITIVE/OBJECT HELIOS::VECTORS ----------------//
2487
2489
2493 [[nodiscard]] Primitive *getPrimitivePointer_private(uint UUID) const;
2494
2496
2500 [[nodiscard]] Patch *getPatchPointer_private(uint UUID) const;
2501
2502
2504
2508 [[nodiscard]] Triangle *getTrianglePointer_private(uint UUID) const;
2509
2511
2515 [[nodiscard]] Voxel *getVoxelPointer_private(uint UUID) const;
2516
2518
2522 [[nodiscard]] CompoundObject *getObjectPointer_private(uint ObjID) const;
2523
2525
2529 [[nodiscard]] Tile *getTileObjectPointer_private(uint ObjID) const;
2530
2532
2536 [[nodiscard]] Sphere *getSphereObjectPointer_private(uint ObjID) const;
2537
2539
2543 [[nodiscard]] Tube *getTubeObjectPointer_private(uint ObjID) const;
2544
2546
2550 [[nodiscard]] Box *getBoxObjectPointer_private(uint ObjID) const;
2551
2553
2557 [[nodiscard]] Disk *getDiskObjectPointer_private(uint ObjID) const;
2558
2560
2564 [[nodiscard]] Polymesh *getPolymeshObjectPointer_private(uint ObjID) const;
2565
2567
2571 [[nodiscard]] Cone *getConeObjectPointer_private(uint ObjID) const;
2572
2574 void invalidateAllUUIDsCache() const {
2575 all_uuids_cache_valid = false;
2576 }
2577
2579
2582 std::unordered_map<uint, Primitive *> primitives;
2583
2585 mutable std::vector<uint> cached_all_uuids;
2587 mutable bool all_uuids_cache_valid = false;
2588
2590 mutable WarningAggregator api_warnings;
2591
2593 std::vector<uint> dirty_deleted_primitives;
2594
2596 std::unordered_map<uint, CompoundObject *> objects;
2597
2599 std::map<std::string, std::vector<float>> timeseries_data;
2600
2602
2603 std::map<std::string, std::vector<double>> timeseries_datevalue;
2604
2605 //------------ TEXTURES ----------------//
2606
2607 std::map<std::string, Texture> textures;
2608
2609 void addTexture(const char *texture_file);
2610
2611
2612 bool doesTextureFileExist(const char *texture_file) const;
2613
2614 bool validateTextureFileExtenstion(const char *texture_file) const;
2615
2616 //------------ MATERIALS ----------------//
2617
2619 static constexpr const char *DEFAULT_MATERIAL_LABEL = "__default__";
2620
2622 std::map<uint, Material> materials;
2623
2625 std::map<std::string, uint> material_label_to_id;
2626
2628 uint currentMaterialID;
2629
2631
2638 uint addMaterial_internal(const std::string &label, const RGBAcolor &color, const std::string &texture = "");
2639
2641 std::string generateMaterialLabel(const RGBAcolor &color, const std::string &texture, bool texture_override) const;
2642
2644 bool isMaterialShared(uint materialID) const;
2645
2647 uint copyMaterialForPrimitive(uint primitiveUUID);
2648
2649 //----------- GLOBAL DATA -------------//
2650
2651 std::map<std::string, GlobalData> globaldata;
2652
2653 std::unordered_map<std::string, size_t> primitive_data_label_counts;
2654 std::unordered_map<std::string, size_t> object_data_label_counts;
2655
2656 //----------- DATA TYPE CONSISTENCY REGISTRIES -------------//
2657
2659 std::unordered_map<std::string, HeliosDataType> primitive_data_type_registry;
2660
2662 std::unordered_map<std::string, HeliosDataType> object_data_type_registry;
2663
2664 //----------- VALUE-LEVEL CACHING REGISTRIES -------------//
2665
2667 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> primitive_string_value_registry;
2668 std::unordered_map<std::string, std::unordered_map<int, size_t>> primitive_int_value_registry;
2669 std::unordered_map<std::string, std::unordered_map<uint, size_t>> primitive_uint_value_registry;
2670
2672 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> object_string_value_registry;
2673 std::unordered_map<std::string, std::unordered_map<int, size_t>> object_int_value_registry;
2674 std::unordered_map<std::string, std::unordered_map<uint, size_t>> object_uint_value_registry;
2675
2677 std::unordered_set<std::string> cached_primitive_data_labels;
2678 std::unordered_set<std::string> cached_object_data_labels;
2679
2681
2684 void incrementPrimitiveDataLabelCounter(const std::string &primitive_data_label);
2685
2687
2690 void decrementPrimitiveDataLabelCounter(const std::string &primitive_data_label);
2691
2692
2694
2697 void incrementObjectDataLabelCounter(const std::string &object_data_label);
2698
2700
2703 void decrementObjectDataLabelCounter(const std::string &object_data_label);
2704
2706 std::string dataTypeToString(HeliosDataType type) const;
2707
2709 bool isTypeCastingSupported(HeliosDataType from_type, HeliosDataType to_type) const;
2710
2711 //---------- CONTEXT PRIVATE MEMBER VARIABLES ---------//
2712
2714
2717 helios::Date sim_date;
2718
2720
2723 helios::Time sim_time;
2724
2726 helios::Location sim_location;
2727
2729 std::minstd_rand0 generator;
2730
2732 std::uniform_real_distribution<float> unif_distribution;
2733
2735 std::normal_distribution<float> norm_distribution;
2736
2737 //---------- CONTEXT I/O ---------//
2738
2739 std::vector<std::string> XMLfiles;
2740
2741 struct OBJmaterial {
2742
2743 RGBcolor color;
2744 std::string texture;
2745 uint materialID;
2746 bool textureHasTransparency = false;
2747 bool textureColorIsOverridden = false;
2748
2749 OBJmaterial(const RGBcolor &a_color, std::string a_texture, uint a_materialID) : color{a_color}, texture{std::move(a_texture)}, materialID{a_materialID} {};
2750 };
2751
2752 std::map<std::string, OBJmaterial> loadMTL(const std::string &filebase, const std::string &material_file, const RGBcolor &default_color);
2753
2754 void loadMaterialData(pugi::xml_node mat_node, const std::string &material_label);
2755
2756 void loadPData(pugi::xml_node p, uint UUID);
2757
2758 void loadOData(pugi::xml_node p, uint ID);
2759
2760 void loadOsubPData(pugi::xml_node p, uint ID);
2761
2762 void writeDataToXMLstream(const char *data_group, const std::vector<std::string> &data_labels, void *ptr, std::ofstream &outfile) const;
2763
2764
2765 //---------- CONTEXT INITIALIZATION FLAGS ---------//
2766
2767 uint currentUUID;
2768
2769 uint currentObjectID;
2770
2771 //---------- MEMORY HANDLING -----------------//
2772
2774
2778 static void out_of_memory_handler();
2779
2781
2784 static void install_out_of_memory_handler();
2785
2786 public:
2788 Context();
2789
2791 ~Context();
2792
2794 Context(const Context &) = delete;
2795
2797 void operator=(const Context &) = delete;
2798
2800
2805 static int selfTest(int argc, char **argv);
2806
2808
2811 void seedRandomGenerator(uint seed);
2812
2814
2817 std::minstd_rand0 *getRandomGenerator();
2818
2820
2824 void markGeometryClean();
2825
2827
2831 void markGeometryDirty();
2832
2834
2838 [[nodiscard]] bool isGeometryDirty() const;
2839
2841
2844 void markPrimitiveDirty(uint UUID) const;
2845
2847
2850 void markPrimitiveDirty(const std::vector<uint> &UUIDs) const;
2851
2853
2856 void markPrimitiveClean(uint UUID) const;
2857
2859
2862 void markPrimitiveClean(const std::vector<uint> &UUIDs) const;
2863
2865
2869 [[nodiscard]] bool isPrimitiveDirty(uint UUID) const;
2870
2872
2875 uint addPatch();
2876
2878
2885 uint addPatch(const helios::vec3 &center, const helios::vec2 &size);
2886
2888
2896 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
2897
2899
2906 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
2907
2909
2915 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
2916
2918
2926 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
2927
2929
2939 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file, const helios::vec2 &uv_center, const helios::vec2 &uv_size);
2940
2942
2949 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2950
2952
2960 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBcolor &color);
2961
2963
2971 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBAcolor &color);
2972
2974
2986 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const char *texture_file, const helios::vec2 &uv0, const helios::vec2 &uv1, const helios::vec2 &uv2);
2987
2989
2996 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size);
2997
2999
3007 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation);
3008
3010
3017 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation, const helios::RGBcolor &color);
3018
3020
3027 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation, const helios::RGBAcolor &color);
3028
3030
3034 void translatePrimitive(uint UUID, const vec3 &shift);
3035
3037
3041 void translatePrimitive(const std::vector<uint> &UUIDs, const vec3 &shift);
3042
3044
3049 void rotatePrimitive(uint UUID, float rotation_rad, const char *axis);
3050
3052
3057 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const char *axis);
3058
3060
3065 void rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &axis);
3066
3068
3073 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const vec3 &axis);
3074
3076
3082 void rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &origin, const helios::vec3 &axis);
3083
3085
3091 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const helios::vec3 &origin, const vec3 &axis);
3092
3094
3099 void setPrimitiveNormal(uint UUID, const helios::vec3 &origin, const helios::vec3 &new_normal);
3100
3102
3107 void setPrimitiveNormal(const std::vector<uint> &UUIDs, const helios::vec3 &origin, const vec3 &new_normal);
3108
3110
3115 void setPrimitiveElevation(uint UUID, const helios::vec3 &origin, float new_elevation);
3116
3118
3123 void setPrimitiveAzimuth(uint UUID, const helios::vec3 &origin, float new_azimuth);
3124
3126
3130 void scalePrimitive(uint UUID, const helios::vec3 &S);
3131
3133
3137 void scalePrimitive(const std::vector<uint> &UUIDs, const helios::vec3 &S);
3138
3140
3145 void scalePrimitiveAboutPoint(uint UUID, const helios::vec3 &S, const helios::vec3 &point);
3146
3148
3153 void scalePrimitiveAboutPoint(const std::vector<uint> &UUIDs, const helios::vec3 &S, const helios::vec3 &point);
3154
3156
3159 void deletePrimitive(uint UUID);
3160
3162
3165 void deletePrimitive(const std::vector<uint> &UUIDs);
3166
3168
3172 uint copyPrimitive(uint UUID);
3173
3175
3179 std::vector<uint> copyPrimitive(const std::vector<uint> &UUIDs);
3180
3182
3186 void copyPrimitiveData(uint sourceUUID, uint destinationUUID);
3187
3189
3194 void renamePrimitiveData(uint UUID, const char *old_label, const char *new_label);
3195
3197
3202 void duplicatePrimitiveData(uint UUID, const char *old_label, const char *new_label);
3203
3205
3208 [[nodiscard]] bool doesPrimitiveExist(uint UUID) const;
3209
3211
3215 [[nodiscard]] bool doesPrimitiveExist(const std::vector<uint> &UUIDs) const;
3216
3218
3223 [[nodiscard]] helios::vec2 getPatchSize(uint UUID) const;
3224
3226
3231 [[nodiscard]] helios::vec3 getPatchCenter(uint UUID) const;
3232
3234
3240 [[nodiscard]] helios::vec3 getTriangleVertex(uint UUID, uint number) const;
3241
3243
3249 void setTriangleVertices(uint UUID, const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
3250
3252
3257 [[nodiscard]] helios::vec3 getVoxelCenter(uint UUID) const;
3258
3260
3265 [[nodiscard]] helios::vec3 getVoxelSize(uint UUID) const;
3266
3268
3272 [[nodiscard]] size_t getPrimitiveCount(bool include_hidden_primitives = true) const;
3273
3275
3279 [[nodiscard]] size_t getTriangleCount(bool include_hidden_primitives = true) const;
3280
3282
3286 [[nodiscard]] size_t getPatchCount(bool include_hidden_primitives = true) const;
3287
3289 [[nodiscard]] std::vector<uint> getAllUUIDs() const;
3290
3292
3296 [[nodiscard]] std::vector<uint> getDirtyUUIDs(bool include_deleted_UUIDs = false) const;
3297
3299
3302 [[nodiscard]] std::vector<uint> getDeletedUUIDs() const;
3303
3305
3308 void hidePrimitive(uint UUID) const;
3309
3311
3314 void hidePrimitive(const std::vector<uint> &UUIDs) const;
3315
3317
3320 void showPrimitive(uint UUID) const;
3321
3323
3326 void showPrimitive(const std::vector<uint> &UUIDs) const;
3327
3329
3333 [[nodiscard]] bool isPrimitiveHidden(uint UUID) const;
3334
3336
3339 void cleanDeletedUUIDs(std::vector<uint> &UUIDs) const;
3340
3342
3345 void cleanDeletedUUIDs(std::vector<std::vector<uint>> &UUIDs) const;
3346
3348
3351 void cleanDeletedUUIDs(std::vector<std::vector<std::vector<uint>>> &UUIDs) const;
3352
3353 //-------- Primitive Data Methods ---------- //
3354
3356
3362 template<typename T>
3363 void setPrimitiveData(uint UUID, const char *label, const T &data) {
3364#ifdef HELIOS_DEBUG
3365 if (primitives.find(UUID) == primitives.end()) {
3366 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3367 }
3368#endif
3369 // Check if this primitive already has cached data for registry maintenance
3370 std::string label_str = std::string(label);
3371 bool had_cached_value = false;
3372
3373 // Handle caching only for supported types, and avoid character arrays
3374 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3375 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3376 T old_cached_value{};
3377 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
3378 decrementPrimitiveValueRegistry(label_str, old_cached_value);
3379 had_cached_value = true;
3380 }
3381 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3382 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3383 std::string old_cached_value;
3384 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
3385 decrementPrimitiveValueRegistry(label_str, old_cached_value);
3386 had_cached_value = true;
3387 }
3388 }
3389
3390 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3391 incrementPrimitiveDataLabelCounter(label);
3392 }
3393
3394 // Validate data type consistency and register/validate type
3395 HeliosDataType data_type;
3396 if constexpr (std::is_same_v<T, int>) {
3397 data_type = HELIOS_TYPE_INT;
3398 } else if constexpr (std::is_same_v<T, uint>) {
3399 data_type = HELIOS_TYPE_UINT;
3400 } else if constexpr (std::is_same_v<T, float>) {
3401 data_type = HELIOS_TYPE_FLOAT;
3402 } else if constexpr (std::is_same_v<T, double>) {
3403 data_type = HELIOS_TYPE_DOUBLE;
3404 } else if constexpr (std::is_same_v<T, vec2>) {
3405 data_type = HELIOS_TYPE_VEC2;
3406 } else if constexpr (std::is_same_v<T, vec3>) {
3407 data_type = HELIOS_TYPE_VEC3;
3408 } else if constexpr (std::is_same_v<T, vec4>) {
3409 data_type = HELIOS_TYPE_VEC4;
3410 } else if constexpr (std::is_same_v<T, int2>) {
3411 data_type = HELIOS_TYPE_INT2;
3412 } else if constexpr (std::is_same_v<T, int3>) {
3413 data_type = HELIOS_TYPE_INT3;
3414 } else if constexpr (std::is_same_v<T, int4>) {
3415 data_type = HELIOS_TYPE_INT4;
3416 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3417 data_type = HELIOS_TYPE_STRING;
3418 }
3419 HeliosDataType target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
3420
3421 // Store data with type casting if needed
3422 if (target_type != data_type && isTypeCastingSupported(data_type, target_type)) {
3423 storeDataWithTypeCasting(UUID, label, data, target_type);
3424 } else {
3425 primitives.at(UUID)->setPrimitiveData(label, data);
3426 }
3427
3428 // Update value registry if caching is enabled for this label (only for new data)
3429 if (isPrimitiveDataValueCachingEnabled(label_str) && !had_cached_value) {
3430 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3431 incrementPrimitiveValueRegistry(label_str, data);
3432 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3433 incrementPrimitiveValueRegistry(label_str, std::string(data));
3434 }
3435 } else if (isPrimitiveDataValueCachingEnabled(label_str) && had_cached_value) {
3436 // For updates, just add the new value (old value was already decremented)
3437 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3438 incrementPrimitiveValueRegistry(label_str, data);
3439 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3440 incrementPrimitiveValueRegistry(label_str, std::string(data));
3441 }
3442 }
3443 }
3444
3446
3452 template<typename T>
3453 void setPrimitiveData(uint UUID, const char *label, const std::vector<T> &data) {
3454#ifdef HELIOS_DEBUG
3455 if (primitives.find(UUID) == primitives.end()) {
3456 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3457 }
3458#endif
3459 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3460 incrementPrimitiveDataLabelCounter(label);
3461 }
3462
3463 // For vector data, register the base type (not vector type)
3464 HeliosDataType data_type;
3465 if constexpr (std::is_same_v<T, int>) {
3466 data_type = HELIOS_TYPE_INT;
3467 } else if constexpr (std::is_same_v<T, uint>) {
3468 data_type = HELIOS_TYPE_UINT;
3469 } else if constexpr (std::is_same_v<T, float>) {
3470 data_type = HELIOS_TYPE_FLOAT;
3471 } else if constexpr (std::is_same_v<T, double>) {
3472 data_type = HELIOS_TYPE_DOUBLE;
3473 } else if constexpr (std::is_same_v<T, vec2>) {
3474 data_type = HELIOS_TYPE_VEC2;
3475 } else if constexpr (std::is_same_v<T, vec3>) {
3476 data_type = HELIOS_TYPE_VEC3;
3477 } else if constexpr (std::is_same_v<T, vec4>) {
3478 data_type = HELIOS_TYPE_VEC4;
3479 } else if constexpr (std::is_same_v<T, int2>) {
3480 data_type = HELIOS_TYPE_INT2;
3481 } else if constexpr (std::is_same_v<T, int3>) {
3482 data_type = HELIOS_TYPE_INT3;
3483 } else if constexpr (std::is_same_v<T, int4>) {
3484 data_type = HELIOS_TYPE_INT4;
3485 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3486 data_type = HELIOS_TYPE_STRING;
3487 }
3488 registerOrValidatePrimitiveDataType<T>(label, data_type);
3489
3490 primitives.at(UUID)->setPrimitiveData(label, data);
3491 }
3492
3494
3501 template<typename T>
3502 void setPrimitiveData(const std::vector<uint> &UUIDs, const char *label, const std::vector<T> &data) {
3503#ifdef HELIOS_DEBUG
3504 if (UUIDs.size() != data.size()) {
3505 helios_runtime_error("ERROR (Context::setPrimitiveData): UUIDs and data vectors must be the same size.");
3506 }
3507#endif
3508
3509 // Validate data type consistency and register/validate type (only once for all elements)
3510 HeliosDataType target_type = HELIOS_TYPE_UNKNOWN;
3511 if (!UUIDs.empty()) {
3512 HeliosDataType data_type;
3513 if constexpr (std::is_same_v<T, int>) {
3514 data_type = HELIOS_TYPE_INT;
3515 } else if constexpr (std::is_same_v<T, uint>) {
3516 data_type = HELIOS_TYPE_UINT;
3517 } else if constexpr (std::is_same_v<T, float>) {
3518 data_type = HELIOS_TYPE_FLOAT;
3519 } else if constexpr (std::is_same_v<T, double>) {
3520 data_type = HELIOS_TYPE_DOUBLE;
3521 } else if constexpr (std::is_same_v<T, vec2>) {
3522 data_type = HELIOS_TYPE_VEC2;
3523 } else if constexpr (std::is_same_v<T, vec3>) {
3524 data_type = HELIOS_TYPE_VEC3;
3525 } else if constexpr (std::is_same_v<T, vec4>) {
3526 data_type = HELIOS_TYPE_VEC4;
3527 } else if constexpr (std::is_same_v<T, int2>) {
3528 data_type = HELIOS_TYPE_INT2;
3529 } else if constexpr (std::is_same_v<T, int3>) {
3530 data_type = HELIOS_TYPE_INT3;
3531 } else if constexpr (std::is_same_v<T, int4>) {
3532 data_type = HELIOS_TYPE_INT4;
3533 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3534 data_type = HELIOS_TYPE_STRING;
3535 }
3536 target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
3537 }
3538
3539 for (uint UUID: UUIDs) {
3540#ifdef HELIOS_DEBUG
3541 if (primitives.find(UUID) == primitives.end()) {
3542 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3543 }
3544#endif
3545 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3546 incrementPrimitiveDataLabelCounter(label);
3547 }
3548 }
3549
3550#ifdef USE_OPENMP
3551#pragma omp parallel for
3552#endif
3553 for (int i = 0; i < (int) UUIDs.size(); ++i) {
3554 primitives.at(UUIDs[i])->setPrimitiveData(label, data[i]);
3555 }
3556 }
3557
3559
3565 template<typename T>
3566 void setPrimitiveData(const std::vector<uint> &UUIDs, const char *label, const T &data) {
3567
3568 // Validate data type consistency and register/validate type
3569 if (!UUIDs.empty()) {
3570 HeliosDataType data_type;
3571 if constexpr (std::is_same_v<T, int>) {
3572 data_type = HELIOS_TYPE_INT;
3573 } else if constexpr (std::is_same_v<T, uint>) {
3574 data_type = HELIOS_TYPE_UINT;
3575 } else if constexpr (std::is_same_v<T, float>) {
3576 data_type = HELIOS_TYPE_FLOAT;
3577 } else if constexpr (std::is_same_v<T, double>) {
3578 data_type = HELIOS_TYPE_DOUBLE;
3579 } else if constexpr (std::is_same_v<T, vec2>) {
3580 data_type = HELIOS_TYPE_VEC2;
3581 } else if constexpr (std::is_same_v<T, vec3>) {
3582 data_type = HELIOS_TYPE_VEC3;
3583 } else if constexpr (std::is_same_v<T, vec4>) {
3584 data_type = HELIOS_TYPE_VEC4;
3585 } else if constexpr (std::is_same_v<T, int2>) {
3586 data_type = HELIOS_TYPE_INT2;
3587 } else if constexpr (std::is_same_v<T, int3>) {
3588 data_type = HELIOS_TYPE_INT3;
3589 } else if constexpr (std::is_same_v<T, int4>) {
3590 data_type = HELIOS_TYPE_INT4;
3591 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3592 data_type = HELIOS_TYPE_STRING;
3593 }
3594 registerOrValidatePrimitiveDataType<T>(label, data_type);
3595 }
3596
3597 for (uint UUID: UUIDs) {
3598#ifdef HELIOS_DEBUG
3599 if (primitives.find(UUID) == primitives.end()) {
3600 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3601 }
3602#endif
3603 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3604 incrementPrimitiveDataLabelCounter(label);
3605 }
3606 }
3607
3608#ifdef USE_OPENMP
3609#pragma omp parallel for
3610#endif
3611 for (int i = 0; i < (int) UUIDs.size(); ++i) {
3612 primitives.at(UUIDs[i])->setPrimitiveData(label, data);
3613 }
3614 }
3615
3617
3623 template<typename T>
3624 void getPrimitiveData(uint UUID, const char *label, T &data) const {
3625#ifdef HELIOS_DEBUG
3626 if (primitives.find(UUID) == primitives.end()) {
3627 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3628 }
3629#endif
3630 primitives.at(UUID)->getPrimitiveData(label, data);
3631 }
3632
3634
3641 template<typename T>
3642 void getPrimitiveData(uint UUID, const char *label, std::vector<T> &data) const {
3643#ifdef HELIOS_DEBUG
3644 if (primitives.find(UUID) == primitives.end()) {
3645 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3646 }
3647#endif
3648 primitives.at(UUID)->getPrimitiveData(label, data);
3649 }
3650
3652
3658 [[deprecated]]
3659 HeliosDataType getPrimitiveDataType(uint UUID, const char *label) const;
3660
3662
3668 HeliosDataType getPrimitiveDataType(const char *label) const;
3669
3671
3676 uint getPrimitiveDataSize(uint UUID, const char *label) const;
3677
3679
3684 bool doesPrimitiveDataExist(uint UUID, const char *label) const;
3685
3687
3691 void clearPrimitiveData(uint UUID, const char *label);
3692
3694
3698 void clearPrimitiveData(const std::vector<uint> &UUIDs, const char *label);
3699
3701
3704 [[nodiscard]] std::vector<std::string> listAllPrimitiveDataLabels() const;
3705
3706
3707 //----------- VALUE-LEVEL CACHING CONFIGURATION ----------//
3708
3710
3713 void enablePrimitiveDataValueCaching(const std::string &label);
3714
3716
3719 void disablePrimitiveDataValueCaching(const std::string &label);
3720
3722
3726 [[nodiscard]] bool isPrimitiveDataValueCachingEnabled(const std::string &label) const;
3727
3729
3732 void enableObjectDataValueCaching(const std::string &label);
3733
3735
3738 void disableObjectDataValueCaching(const std::string &label);
3739
3741
3745 [[nodiscard]] bool isObjectDataValueCachingEnabled(const std::string &label) const;
3746
3747 //----------- UNIQUE VALUE QUERY METHODS ----------//
3748
3749
3751
3755 [[nodiscard]] PrimitiveType getPrimitiveType(uint UUID) const;
3756
3758
3762 void setPrimitiveParentObjectID(uint UUID, uint objID);
3763
3765
3769 void setPrimitiveParentObjectID(const std::vector<uint> &UUIDs, uint objID);
3770
3772
3775 [[nodiscard]] uint getPrimitiveParentObjectID(uint UUID) const;
3776
3778
3781 [[nodiscard]] std::vector<uint> getPrimitiveParentObjectID(const std::vector<uint> &UUIDs) const;
3782
3784
3787 [[nodiscard]] std::vector<uint> getUniquePrimitiveParentObjectIDs(const std::vector<uint> &UUIDs) const;
3788
3790
3794 [[nodiscard]] std::vector<uint> getUniquePrimitiveParentObjectIDs(const std::vector<uint> &UUIDs, bool include_ObjID_zero) const;
3795
3797
3800 [[nodiscard]] float getPrimitiveArea(uint UUID) const;
3801
3803
3808 void getPrimitiveBoundingBox(uint UUID, vec3 &min_corner, vec3 &max_corner) const;
3809
3811
3816 void getPrimitiveBoundingBox(const std::vector<uint> &UUIDs, vec3 &min_corner, vec3 &max_corner) const;
3817
3819
3822 void hideObject(uint ObjID);
3823
3825
3828 void hideObject(const std::vector<uint> &ObjIDs);
3829
3831
3834 void showObject(uint ObjID);
3835
3837
3840 void showObject(const std::vector<uint> &ObjIDs);
3841
3843
3847 [[nodiscard]] bool isObjectHidden(uint ObjID) const;
3848
3850
3853 [[nodiscard]] float getObjectArea(uint ObjID) const;
3854
3856
3859 [[nodiscard]] helios::vec3 getObjectAverageNormal(uint ObjID) const;
3860
3862
3865 [[nodiscard]] uint getObjectPrimitiveCount(uint ObjID) const;
3866
3868
3871 [[nodiscard]] helios::vec3 getObjectCenter(uint ObjID) const;
3872
3874
3878 void setObjectColor(uint ObjID, const helios::RGBcolor &color) const;
3879
3881
3885 void setObjectColor(const std::vector<uint> &ObjIDs, const helios::RGBcolor &color) const;
3886
3888
3892 void setObjectColor(uint ObjID, const helios::RGBAcolor &color) const;
3893
3895
3899 void setObjectColor(const std::vector<uint> &ObjIDs, const helios::RGBAcolor &color) const;
3900
3902
3905 [[nodiscard]] std::string getObjectTextureFile(uint ObjID) const;
3906
3908
3912 void getObjectTransformationMatrix(uint ObjID, float (&T)[16]) const;
3913
3915
3919 void setObjectTransformationMatrix(uint ObjID, float (&T)[16]) const;
3920
3922
3926 void setObjectTransformationMatrix(const std::vector<uint> &ObjIDs, float (&T)[16]) const;
3927
3929
3937 void setObjectAverageNormal(uint ObjID, const vec3 &origin, const vec3 &new_normal) const;
3938
3940
3946 void setObjectOrigin(uint ObjID, const vec3 &origin) const;
3947
3949
3952 [[nodiscard]] bool objectHasTexture(uint ObjID) const;
3953
3955
3959 [[nodiscard]] bool doesObjectContainPrimitive(uint ObjID, uint UUID) const;
3960
3962
3965 void overrideObjectTextureColor(uint ObjID) const;
3966
3968
3971 void overrideObjectTextureColor(const std::vector<uint> &ObjIDs) const;
3972
3975
3978 void useObjectTextureColor(uint ObjID) const;
3979
3982
3985 void useObjectTextureColor(const std::vector<uint> &ObjIDs);
3986
3988
3993 void getObjectBoundingBox(uint ObjID, vec3 &min_corner, vec3 &max_corner) const;
3994
3996
4001 void getObjectBoundingBox(const std::vector<uint> &ObjIDs, vec3 &min_corner, vec3 &max_corner) const;
4002
4004
4007 void printObjectInfo(uint ObjID) const;
4008
4010 [[nodiscard]] std::vector<std::string> listObjectData(uint ObjID) const;
4011
4013 [[nodiscard]] std::vector<std::string> listPrimitiveData(uint UUID) const;
4014
4016
4020 [[nodiscard]] float getPrimitiveSolidFraction(uint UUID) const;
4021
4023
4026 [[nodiscard]] helios::vec3 getPrimitiveNormal(uint UUID) const;
4027
4029
4033 void getPrimitiveTransformationMatrix(uint UUID, float (&T)[16]) const;
4034
4036
4040 void setPrimitiveTransformationMatrix(uint UUID, float (&T)[16]);
4041
4043
4047 void setPrimitiveTransformationMatrix(const std::vector<uint> &UUIDs, float (&T)[16]);
4048
4050
4053 [[nodiscard]] std::vector<helios::vec3> getPrimitiveVertices(uint UUID) const;
4054
4056
4059 [[nodiscard]] helios::RGBcolor getPrimitiveColor(uint UUID) const;
4060
4062
4065 [[nodiscard]] helios::RGBcolor getPrimitiveColorRGB(uint UUID) const;
4066
4068
4071 [[nodiscard]] helios::RGBAcolor getPrimitiveColorRGBA(uint UUID) const;
4072
4074
4078 void setPrimitiveColor(uint UUID, const helios::RGBcolor &color) const;
4079
4081
4085 void setPrimitiveColor(const std::vector<uint> &UUIDs, const helios::RGBcolor &color) const;
4086
4088
4092 void setPrimitiveColor(uint UUID, const helios::RGBAcolor &color) const;
4093
4095
4099 void setPrimitiveColor(const std::vector<uint> &UUIDs, const helios::RGBAcolor &color) const;
4100
4102
4106 [[nodiscard]] std::string getPrimitiveTextureFile(uint UUID) const;
4107
4109
4113 void setPrimitiveTextureFile(uint UUID, const std::string &texturefile) const;
4114
4116
4120 [[nodiscard]] helios::int2 getPrimitiveTextureSize(uint UUID) const;
4121
4123
4126 [[nodiscard]] std::vector<vec2> getPrimitiveTextureUV(uint UUID) const;
4127
4129
4133 [[nodiscard]] bool primitiveTextureHasTransparencyChannel(uint UUID) const;
4134
4136
4140 [[nodiscard]] const std::vector<std::vector<bool>> *getPrimitiveTextureTransparencyData(uint UUID) const;
4141
4143
4146 void overridePrimitiveTextureColor(uint UUID) const;
4147
4149
4152 void overridePrimitiveTextureColor(const std::vector<uint> &UUIDs) const;
4153
4155
4158 void usePrimitiveTextureColor(uint UUID) const;
4159
4161
4164 void usePrimitiveTextureColor(const std::vector<uint> &UUIDs) const;
4165
4167
4170 [[nodiscard]] bool isPrimitiveTextureColorOverridden(uint UUID) const;
4171
4173
4176 void printPrimitiveInfo(uint UUID) const;
4177
4179
4183 void reportAPIWarnings() const;
4184
4185 //-------- Material Management Methods ---------- //
4186
4188
4193 void addMaterial(const std::string &material_label);
4194
4196
4201 void renameMaterial(const std::string &old_label, const std::string &new_label);
4202
4204
4208 [[nodiscard]] bool doesMaterialExist(const std::string &material_label) const;
4209
4211
4214 [[nodiscard]] std::vector<std::string> listMaterials() const;
4215
4217
4221 [[nodiscard]] RGBAcolor getMaterialColor(const std::string &material_label) const;
4222
4224
4228 [[nodiscard]] std::string getMaterialTexture(const std::string &material_label) const;
4229
4231
4235 [[nodiscard]] bool isMaterialTextureColorOverridden(const std::string &material_label) const;
4236
4238
4243 void setMaterialColor(const std::string &material_label, const RGBAcolor &color);
4244
4246
4251 void setMaterialTexture(const std::string &material_label, const std::string &texture_file);
4252
4254
4259 void setMaterialTextureColorOverride(const std::string &material_label, bool override);
4260
4262
4266 [[nodiscard]] uint getMaterialTwosidedFlag(const std::string &material_label) const;
4267
4269
4274 void setMaterialTwosidedFlag(const std::string &material_label, uint twosided_flag);
4275
4277
4284 [[nodiscard]] uint getPrimitiveTwosidedFlag(uint UUID, uint default_value = 1) const;
4285
4287
4292 void assignMaterialToPrimitive(uint UUID, const std::string &material_label);
4293
4295
4300 void assignMaterialToPrimitive(const std::vector<uint> &UUIDs, const std::string &material_label);
4301
4303
4308 void assignMaterialToObject(uint ObjID, const std::string &material_label);
4309
4311
4316 void assignMaterialToObject(const std::vector<uint> &ObjIDs, const std::string &material_label);
4317
4319
4323 [[nodiscard]] std::string getPrimitiveMaterialLabel(uint UUID) const;
4324
4326
4330 [[nodiscard]] std::vector<uint> getPrimitivesUsingMaterial(const std::string &material_label) const;
4331
4333
4338 void deleteMaterial(const std::string &material_label);
4339
4341
4348 template<typename T>
4349 void setMaterialData(const std::string &material_label, const char *data_label, const T &data) {
4350 uint matID = getMaterialIDFromLabel(material_label);
4351 materials[matID].setMaterialData(data_label, data);
4352 }
4353
4355
4362 template<typename T>
4363 void setMaterialData(const std::string &material_label, const char *data_label, const std::vector<T> &data) {
4364 uint matID = getMaterialIDFromLabel(material_label);
4365 materials[matID].setMaterialData(data_label, data);
4366 }
4367
4369
4375 template<typename T>
4376 void getMaterialData(const std::string &material_label, const char *data_label, T &data) const {
4377 uint matID = getMaterialIDFromLabel(material_label);
4378 materials.at(matID).getMaterialData(data_label, data);
4379 }
4380
4382
4388 template<typename T>
4389 void getMaterialData(const std::string &material_label, const char *data_label, std::vector<T> &data) const {
4390 uint matID = getMaterialIDFromLabel(material_label);
4391 materials.at(matID).getMaterialData(data_label, data);
4392 }
4393
4395
4400 [[nodiscard]] bool doesMaterialDataExist(const std::string &material_label, const char *data_label) const;
4401
4403
4408 [[nodiscard]] HeliosDataType getMaterialDataType(const std::string &material_label, const char *data_label) const;
4409
4411
4415 void clearMaterialData(const std::string &material_label, const char *data_label);
4416
4418
4428 template<typename T>
4429 void getDataWithMaterialFallback(uint UUID, const char *data_label, T &data) const {
4430 Primitive *prim = getPrimitivePointer_private(UUID);
4431 uint materialID = prim->materialID;
4432
4433 // First check if material has this data
4434 if (materials.find(materialID) != materials.end() && materials.at(materialID).doesMaterialDataExist(data_label)) {
4435 materials.at(materialID).getMaterialData(data_label, data);
4436 }
4437 // Otherwise check if primitive has this data
4438 else if (prim->doesPrimitiveDataExist(data_label)) {
4439 prim->getPrimitiveData(data_label, data);
4440 }
4441 // If neither has the data, throw error
4442 else {
4443 helios_runtime_error("ERROR (Context::getDataWithMaterialFallback): Data " + std::string(data_label) + " does not exist for primitive " + std::to_string(UUID) + " (neither in its material nor as primitive data).");
4444 }
4445 }
4446
4448
4452 [[nodiscard]] uint getPrimitiveMaterialID(uint UUID) const;
4453
4455
4459 [[nodiscard]] const Material &getMaterial(uint materialID) const;
4460
4462
4466 [[nodiscard]] uint getMaterialIDFromLabel(const std::string &material_label) const;
4467
4469
4472 [[nodiscard]] uint getMaterialCount() const;
4473
4474 //-------- Compound Object Data Methods ---------- //
4475
4477
4483 template<typename T>
4484 void setObjectData(uint objID, const char *label, const T &data) {
4485#ifdef HELIOS_DEBUG
4486 if (objects.find(objID) == objects.end()) {
4487 helios_runtime_error("ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
4488 }
4489#endif
4490 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4491 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
4492 "Context::setObjectData() was called with an unsupported type.");
4493
4494 // Validate data type consistency and register/validate type
4495 HeliosDataType data_type;
4496 if constexpr (std::is_same_v<T, int>) {
4497 data_type = HELIOS_TYPE_INT;
4498 } else if constexpr (std::is_same_v<T, uint>) {
4499 data_type = HELIOS_TYPE_UINT;
4500 } else if constexpr (std::is_same_v<T, float>) {
4501 data_type = HELIOS_TYPE_FLOAT;
4502 } else if constexpr (std::is_same_v<T, double>) {
4503 data_type = HELIOS_TYPE_DOUBLE;
4504 } else if constexpr (std::is_same_v<T, vec2>) {
4505 data_type = HELIOS_TYPE_VEC2;
4506 } else if constexpr (std::is_same_v<T, vec3>) {
4507 data_type = HELIOS_TYPE_VEC3;
4508 } else if constexpr (std::is_same_v<T, vec4>) {
4509 data_type = HELIOS_TYPE_VEC4;
4510 } else if constexpr (std::is_same_v<T, int2>) {
4511 data_type = HELIOS_TYPE_INT2;
4512 } else if constexpr (std::is_same_v<T, int3>) {
4513 data_type = HELIOS_TYPE_INT3;
4514 } else if constexpr (std::is_same_v<T, int4>) {
4515 data_type = HELIOS_TYPE_INT4;
4516 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4517 data_type = HELIOS_TYPE_STRING;
4518 }
4519 registerOrValidateObjectDataType<T>(label, data_type);
4520
4521 // Check if this object already has cached data for registry maintenance
4522 std::string label_str = std::string(label);
4523 bool had_cached_value = false;
4524
4525 // Handle caching only for supported types, and avoid character arrays
4526 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4527 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
4528 T old_cached_value{};
4529 objects.at(objID)->getObjectData(label, old_cached_value);
4530 decrementObjectValueRegistry(label_str, old_cached_value);
4531 had_cached_value = true;
4532 }
4533 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4534 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
4535 std::string old_cached_value;
4536 objects.at(objID)->getObjectData(label, old_cached_value);
4537 decrementObjectValueRegistry(label_str, old_cached_value);
4538 had_cached_value = true;
4539 }
4540 }
4541
4542 if (!objects.at(objID)->doesObjectDataExist(label)) {
4543 incrementObjectDataLabelCounter(label);
4544 }
4545 objects.at(objID)->setObjectData(label, data);
4546
4547 // Update value registry if caching is enabled for this label (only for new data)
4548 if (isObjectDataValueCachingEnabled(label_str) && !had_cached_value) {
4549 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4550 incrementObjectValueRegistry(label_str, data);
4551 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4552 incrementObjectValueRegistry(label_str, std::string(data));
4553 }
4554 } else if (isObjectDataValueCachingEnabled(label_str) && had_cached_value) {
4555 // For updates, just add the new value (old value was already decremented)
4556 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4557 incrementObjectValueRegistry(label_str, data);
4558 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4559 incrementObjectValueRegistry(label_str, std::string(data));
4560 }
4561 }
4562 }
4563
4565
4571 template<typename T>
4572 void setObjectData(const std::vector<uint> &objIDs, const char *label, const T &data) {
4573 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4574 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
4575 "Context::setObjectData() was called with an unsupported type.");
4576
4577 // Validate data type consistency and register/validate type
4578 if (!objIDs.empty()) {
4579 HeliosDataType data_type;
4580 if constexpr (std::is_same_v<T, int>) {
4581 data_type = HELIOS_TYPE_INT;
4582 } else if constexpr (std::is_same_v<T, uint>) {
4583 data_type = HELIOS_TYPE_UINT;
4584 } else if constexpr (std::is_same_v<T, float>) {
4585 data_type = HELIOS_TYPE_FLOAT;
4586 } else if constexpr (std::is_same_v<T, double>) {
4587 data_type = HELIOS_TYPE_DOUBLE;
4588 } else if constexpr (std::is_same_v<T, vec2>) {
4589 data_type = HELIOS_TYPE_VEC2;
4590 } else if constexpr (std::is_same_v<T, vec3>) {
4591 data_type = HELIOS_TYPE_VEC3;
4592 } else if constexpr (std::is_same_v<T, vec4>) {
4593 data_type = HELIOS_TYPE_VEC4;
4594 } else if constexpr (std::is_same_v<T, int2>) {
4595 data_type = HELIOS_TYPE_INT2;
4596 } else if constexpr (std::is_same_v<T, int3>) {
4597 data_type = HELIOS_TYPE_INT3;
4598 } else if constexpr (std::is_same_v<T, int4>) {
4599 data_type = HELIOS_TYPE_INT4;
4600 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4601 data_type = HELIOS_TYPE_STRING;
4602 }
4603 registerOrValidateObjectDataType<T>(label, data_type);
4604 }
4605
4606 // Check if caching is enabled for this label
4607 std::string label_str = std::string(label);
4608 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
4609
4610 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
4611 if (caching_enabled) {
4612 // Handle caching only for supported types
4613 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4614 for (uint objID: objIDs) {
4615 if (objects.at(objID)->doesObjectDataExist(label)) {
4616 T old_cached_value{};
4617 objects.at(objID)->getObjectData(label, old_cached_value);
4618 decrementObjectValueRegistry(label_str, old_cached_value);
4619 }
4620 }
4621 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4622 for (uint objID: objIDs) {
4623 if (objects.at(objID)->doesObjectDataExist(label)) {
4624 std::string old_cached_value;
4625 objects.at(objID)->getObjectData(label, old_cached_value);
4626 decrementObjectValueRegistry(label_str, old_cached_value);
4627 }
4628 }
4629 }
4630 }
4631
4632 // Count new data labels
4633 for (uint objID: objIDs) {
4634 if (!objects.at(objID)->doesObjectDataExist(label)) {
4635 incrementObjectDataLabelCounter(label);
4636 }
4637 }
4638
4639#ifdef USE_OPENMP
4640#pragma omp parallel for
4641#endif
4642 for (int i = 0; i < (int) objIDs.size(); ++i) {
4643 objects.at(objIDs[i])->setObjectData(label, data);
4644 }
4645
4646 // Update value registry if caching is enabled (increment the new value for all objects)
4647 if (caching_enabled) {
4648 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4649 // Increment the new value once for each object that received it
4650 for (size_t i = 0; i < objIDs.size(); ++i) {
4651 incrementObjectValueRegistry(label_str, data);
4652 }
4653 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4654 // Increment the new value once for each object that received it
4655 for (size_t i = 0; i < objIDs.size(); ++i) {
4656 incrementObjectValueRegistry(label_str, std::string(data));
4657 }
4658 }
4659 }
4660 }
4661
4663
4669 template<typename T>
4670 void setObjectData(const std::vector<std::vector<uint>> &objIDs, const char *label, const T &data) {
4671 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4672 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
4673 "Context::setObjectData() was called with an unsupported type.");
4674
4675 // Validate data type consistency and register/validate type
4676 if (!objIDs.empty() && !objIDs[0].empty()) {
4677 HeliosDataType data_type;
4678 if constexpr (std::is_same_v<T, int>) {
4679 data_type = HELIOS_TYPE_INT;
4680 } else if constexpr (std::is_same_v<T, uint>) {
4681 data_type = HELIOS_TYPE_UINT;
4682 } else if constexpr (std::is_same_v<T, float>) {
4683 data_type = HELIOS_TYPE_FLOAT;
4684 } else if constexpr (std::is_same_v<T, double>) {
4685 data_type = HELIOS_TYPE_DOUBLE;
4686 } else if constexpr (std::is_same_v<T, vec2>) {
4687 data_type = HELIOS_TYPE_VEC2;
4688 } else if constexpr (std::is_same_v<T, vec3>) {
4689 data_type = HELIOS_TYPE_VEC3;
4690 } else if constexpr (std::is_same_v<T, vec4>) {
4691 data_type = HELIOS_TYPE_VEC4;
4692 } else if constexpr (std::is_same_v<T, int2>) {
4693 data_type = HELIOS_TYPE_INT2;
4694 } else if constexpr (std::is_same_v<T, int3>) {
4695 data_type = HELIOS_TYPE_INT3;
4696 } else if constexpr (std::is_same_v<T, int4>) {
4697 data_type = HELIOS_TYPE_INT4;
4698 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4699 data_type = HELIOS_TYPE_STRING;
4700 }
4701 registerOrValidateObjectDataType<T>(label, data_type);
4702 }
4703
4704 // Check if caching is enabled for this label
4705 std::string label_str = std::string(label);
4706 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
4707 size_t total_objects = 0;
4708
4709 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
4710 if (caching_enabled) {
4711 // Handle caching only for supported types
4712 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4713 for (const auto &j: objIDs) {
4714 for (uint objID: j) {
4715 total_objects++;
4716 if (objects.at(objID)->doesObjectDataExist(label)) {
4717 T old_cached_value{};
4718 objects.at(objID)->getObjectData(label, old_cached_value);
4719 decrementObjectValueRegistry(label_str, old_cached_value);
4720 }
4721 }
4722 }
4723 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4724 for (const auto &j: objIDs) {
4725 for (uint objID: j) {
4726 total_objects++;
4727 if (objects.at(objID)->doesObjectDataExist(label)) {
4728 std::string old_cached_value;
4729 objects.at(objID)->getObjectData(label, old_cached_value);
4730 decrementObjectValueRegistry(label_str, old_cached_value);
4731 }
4732 }
4733 }
4734 }
4735 } else {
4736 // Count total objects for later cache increment
4737 for (const auto &j: objIDs) {
4738 total_objects += j.size();
4739 }
4740 }
4741
4742 for (const auto &j: objIDs) {
4743 for (uint objID: j) {
4744 if (!objects.at(objID)->doesObjectDataExist(label)) {
4745 incrementObjectDataLabelCounter(label);
4746 }
4747 }
4748 }
4749
4750#ifdef USE_OPENMP
4751#pragma omp parallel for
4752#endif
4753 for (int j = 0; j < (int) objIDs.size(); ++j) {
4754 for (size_t i = 0; i < objIDs[j].size(); ++i) {
4755 objects.at(objIDs[j][i])->setObjectData(label, data);
4756 }
4757 }
4758
4759 // Update value registry if caching is enabled (increment the new value for all objects)
4760 if (caching_enabled) {
4761 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4762 // Increment the new value once for each object that received it
4763 for (size_t i = 0; i < total_objects; ++i) {
4764 incrementObjectValueRegistry(label_str, data);
4765 }
4766 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4767 // Increment the new value once for each object that received it
4768 for (size_t i = 0; i < total_objects; ++i) {
4769 incrementObjectValueRegistry(label_str, std::string(data));
4770 }
4771 }
4772 }
4773 }
4774
4776
4782 template<typename T>
4783 void setObjectData(const std::vector<std::vector<std::vector<uint>>> &objIDs, const char *label, const T &data) {
4784 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4785 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
4786 "Context::setObjectData() was called with an unsupported type.");
4787
4788 // Validate data type consistency and register/validate type
4789 if (!objIDs.empty() && !objIDs[0].empty() && !objIDs[0][0].empty()) {
4790 HeliosDataType data_type;
4791 if constexpr (std::is_same_v<T, int>) {
4792 data_type = HELIOS_TYPE_INT;
4793 } else if constexpr (std::is_same_v<T, uint>) {
4794 data_type = HELIOS_TYPE_UINT;
4795 } else if constexpr (std::is_same_v<T, float>) {
4796 data_type = HELIOS_TYPE_FLOAT;
4797 } else if constexpr (std::is_same_v<T, double>) {
4798 data_type = HELIOS_TYPE_DOUBLE;
4799 } else if constexpr (std::is_same_v<T, vec2>) {
4800 data_type = HELIOS_TYPE_VEC2;
4801 } else if constexpr (std::is_same_v<T, vec3>) {
4802 data_type = HELIOS_TYPE_VEC3;
4803 } else if constexpr (std::is_same_v<T, vec4>) {
4804 data_type = HELIOS_TYPE_VEC4;
4805 } else if constexpr (std::is_same_v<T, int2>) {
4806 data_type = HELIOS_TYPE_INT2;
4807 } else if constexpr (std::is_same_v<T, int3>) {
4808 data_type = HELIOS_TYPE_INT3;
4809 } else if constexpr (std::is_same_v<T, int4>) {
4810 data_type = HELIOS_TYPE_INT4;
4811 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4812 data_type = HELIOS_TYPE_STRING;
4813 }
4814 registerOrValidateObjectDataType<T>(label, data_type);
4815 }
4816
4817 // Check if caching is enabled for this label
4818 std::string label_str = std::string(label);
4819 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
4820 size_t total_objects = 0;
4821
4822 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
4823 if (caching_enabled) {
4824 // Handle caching only for supported types
4825 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4826 for (const auto &k: objIDs) {
4827 for (const auto &j: k) {
4828 for (uint objID: j) {
4829 total_objects++;
4830 if (objects.at(objID)->doesObjectDataExist(label)) {
4831 T old_cached_value{};
4832 objects.at(objID)->getObjectData(label, old_cached_value);
4833 decrementObjectValueRegistry(label_str, old_cached_value);
4834 }
4835 }
4836 }
4837 }
4838 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4839 for (const auto &k: objIDs) {
4840 for (const auto &j: k) {
4841 for (uint objID: j) {
4842 total_objects++;
4843 if (objects.at(objID)->doesObjectDataExist(label)) {
4844 std::string old_cached_value;
4845 objects.at(objID)->getObjectData(label, old_cached_value);
4846 decrementObjectValueRegistry(label_str, old_cached_value);
4847 }
4848 }
4849 }
4850 }
4851 }
4852 } else {
4853 // Count total objects for later cache increment
4854 for (const auto &k: objIDs) {
4855 for (const auto &j: k) {
4856 total_objects += j.size();
4857 }
4858 }
4859 }
4860
4861 for (const auto &k: objIDs) {
4862 for (const auto &j: k) {
4863 for (uint objID: j) {
4864 if (!objects.at(objID)->doesObjectDataExist(label)) {
4865 incrementObjectDataLabelCounter(label);
4866 }
4867 }
4868 }
4869 }
4870
4871#ifdef USE_OPENMP
4872#pragma omp parallel for
4873#endif
4874 for (int k = 0; k < (int) objIDs.size(); ++k) {
4875 for (size_t j = 0; j < objIDs[k].size(); ++j) {
4876 for (size_t i = 0; i < objIDs[k][j].size(); ++i) {
4877 uint objID = objIDs[k][j][i];
4878 objects.at(objID)->setObjectData(label, data);
4879 }
4880 }
4881 }
4882
4883 // Update value registry if caching is enabled (increment the new value for all objects)
4884 if (caching_enabled) {
4885 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4886 // Increment the new value once for each object that received it
4887 for (size_t i = 0; i < total_objects; ++i) {
4888 incrementObjectValueRegistry(label_str, data);
4889 }
4890 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4891 // Increment the new value once for each object that received it
4892 for (size_t i = 0; i < total_objects; ++i) {
4893 incrementObjectValueRegistry(label_str, std::string(data));
4894 }
4895 }
4896 }
4897 }
4898
4900
4907 template<typename T>
4908 void setObjectData(uint objID, const char *label, const std::vector<T> &data) {
4909#ifdef HELIOS_DEBUG
4910 if (objects.find(objID) == objects.end()) {
4911 helios_runtime_error("ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
4912 }
4913#endif
4914 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4915 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
4916 "Context::setObjectData() was called with an unsupported type.");
4917
4918 // Validate data type consistency and register/validate type
4919 HeliosDataType data_type;
4920 if constexpr (std::is_same_v<T, int>) {
4921 data_type = HELIOS_TYPE_INT;
4922 } else if constexpr (std::is_same_v<T, uint>) {
4923 data_type = HELIOS_TYPE_UINT;
4924 } else if constexpr (std::is_same_v<T, float>) {
4925 data_type = HELIOS_TYPE_FLOAT;
4926 } else if constexpr (std::is_same_v<T, double>) {
4927 data_type = HELIOS_TYPE_DOUBLE;
4928 } else if constexpr (std::is_same_v<T, vec2>) {
4929 data_type = HELIOS_TYPE_VEC2;
4930 } else if constexpr (std::is_same_v<T, vec3>) {
4931 data_type = HELIOS_TYPE_VEC3;
4932 } else if constexpr (std::is_same_v<T, vec4>) {
4933 data_type = HELIOS_TYPE_VEC4;
4934 } else if constexpr (std::is_same_v<T, int2>) {
4935 data_type = HELIOS_TYPE_INT2;
4936 } else if constexpr (std::is_same_v<T, int3>) {
4937 data_type = HELIOS_TYPE_INT3;
4938 } else if constexpr (std::is_same_v<T, int4>) {
4939 data_type = HELIOS_TYPE_INT4;
4940 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4941 data_type = HELIOS_TYPE_STRING;
4942 }
4943 registerOrValidateObjectDataType<T>(label, data_type);
4944
4945 objects.at(objID)->setObjectData(label, data);
4946 }
4947
4949
4956 template<typename T>
4957 void setObjectData(const std::vector<uint> &objIDs, const char *label, const std::vector<T> &data) {
4958#ifdef HELIOS_DEBUG
4959 if (objIDs.size() != data.size()) {
4960 helios_runtime_error("ERROR (Context::setObjectData): Object IDs and data vectors must be the same size.");
4961 }
4962#endif
4963 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4964 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
4965 "Context::setObjectData() was called with an unsupported type.");
4966
4967 // Validate data type consistency and register/validate type
4968 if (!objIDs.empty()) {
4969 HeliosDataType data_type;
4970 if constexpr (std::is_same_v<T, int>) {
4971 data_type = HELIOS_TYPE_INT;
4972 } else if constexpr (std::is_same_v<T, uint>) {
4973 data_type = HELIOS_TYPE_UINT;
4974 } else if constexpr (std::is_same_v<T, float>) {
4975 data_type = HELIOS_TYPE_FLOAT;
4976 } else if constexpr (std::is_same_v<T, double>) {
4977 data_type = HELIOS_TYPE_DOUBLE;
4978 } else if constexpr (std::is_same_v<T, vec2>) {
4979 data_type = HELIOS_TYPE_VEC2;
4980 } else if constexpr (std::is_same_v<T, vec3>) {
4981 data_type = HELIOS_TYPE_VEC3;
4982 } else if constexpr (std::is_same_v<T, vec4>) {
4983 data_type = HELIOS_TYPE_VEC4;
4984 } else if constexpr (std::is_same_v<T, int2>) {
4985 data_type = HELIOS_TYPE_INT2;
4986 } else if constexpr (std::is_same_v<T, int3>) {
4987 data_type = HELIOS_TYPE_INT3;
4988 } else if constexpr (std::is_same_v<T, int4>) {
4989 data_type = HELIOS_TYPE_INT4;
4990 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4991 data_type = HELIOS_TYPE_STRING;
4992 }
4993 registerOrValidateObjectDataType<T>(label, data_type);
4994 }
4995
4996 for (uint objID: objIDs) {
4997 if (!objects.at(objID)->doesObjectDataExist(label)) {
4998 incrementObjectDataLabelCounter(label);
4999 }
5000 }
5001
5002#ifdef USE_OPENMP
5003#pragma omp parallel for
5004#endif
5005 for (int i = 0; i < (int) objIDs.size(); ++i) {
5006 objects.at(objIDs[i])->setObjectData(label, data[i]);
5007 }
5008 }
5009
5011
5018 void setObjectDataFromPrimitiveDataMean(uint objID, const std::string &label);
5019
5021
5027 template<typename T>
5028 void getObjectData(uint objID, const char *label, T &data) const {
5029#ifdef HELIOS_DEBUG
5030 if (objects.find(objID) == objects.end()) {
5031 helios_runtime_error("ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
5032 }
5033#endif
5034 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5035 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
5036 "Context::getObjectData() was called with an unsupported type.");
5037 objects.at(objID)->getObjectData(label, data);
5038 }
5039
5041
5048 template<typename T>
5049 void getObjectData(uint objID, const char *label, std::vector<T> &data) const {
5050#ifdef HELIOS_DEBUG
5051 if (objects.find(objID) == objects.end()) {
5052 helios_runtime_error("ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
5053 }
5054#endif
5055 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5056 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
5057 "Context::getObjectData() was called with an unsupported type.");
5058 objects.at(objID)->getObjectData(label, data);
5059 }
5060
5062
5068 [[deprecated]]
5069 HeliosDataType getObjectDataType(uint objID, const char *label) const;
5070
5072
5078 HeliosDataType getObjectDataType(const char *label) const;
5079
5081
5086 uint getObjectDataSize(uint objID, const char *label) const;
5087
5089
5094 bool doesObjectDataExist(uint objID, const char *label) const;
5095
5097
5101 void clearObjectData(uint objID, const char *label);
5102
5104
5108 void clearObjectData(const std::vector<uint> &objIDs, const char *label);
5109
5111
5114 [[nodiscard]] std::vector<std::string> listAllObjectDataLabels() const;
5115
5117
5121 [[nodiscard]] bool areObjectPrimitivesComplete(uint objID) const;
5122
5124
5127 void cleanDeletedObjectIDs(std::vector<uint> &objIDs) const;
5128
5130
5133 void cleanDeletedObjectIDs(std::vector<std::vector<uint>> &objIDs) const;
5134
5136
5139 void cleanDeletedObjectIDs(std::vector<std::vector<std::vector<uint>>> &objIDs) const;
5140
5141 //-------- Global Data Methods ---------- //
5142
5144
5148 template<typename T>
5149 void setGlobalData(const char *label, const T &data) {
5150 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5151 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *> || std::is_same_v<T, bool>,
5152 "Context::setGlobalData() was called with an unsupported type.");
5153
5154 globaldata[label].size = 1;
5155 if constexpr (std::is_same_v<T, int>) {
5156 globaldata[label].global_data_int = {data};
5157 globaldata[label].type = HELIOS_TYPE_INT;
5158 } else if constexpr (std::is_same_v<T, uint>) {
5159 globaldata[label].global_data_uint = {data};
5160 globaldata[label].type = HELIOS_TYPE_UINT;
5161 } else if constexpr (std::is_same_v<T, float>) {
5162 globaldata[label].global_data_float = {data};
5163 globaldata[label].type = HELIOS_TYPE_FLOAT;
5164 } else if constexpr (std::is_same_v<T, double>) {
5165 globaldata[label].global_data_double = {data};
5166 globaldata[label].type = HELIOS_TYPE_DOUBLE;
5167 } else if constexpr (std::is_same_v<T, vec2>) {
5168 globaldata[label].global_data_vec2 = {data};
5169 globaldata[label].type = HELIOS_TYPE_VEC2;
5170 } else if constexpr (std::is_same_v<T, vec3>) {
5171 globaldata[label].global_data_vec3 = {data};
5172 globaldata[label].type = HELIOS_TYPE_VEC3;
5173 } else if constexpr (std::is_same_v<T, vec4>) {
5174 globaldata[label].global_data_vec4 = {data};
5175 globaldata[label].type = HELIOS_TYPE_VEC4;
5176 } else if constexpr (std::is_same_v<T, int2>) {
5177 globaldata[label].global_data_int2 = {data};
5178 globaldata[label].type = HELIOS_TYPE_INT2;
5179 } else if constexpr (std::is_same_v<T, int3>) {
5180 globaldata[label].global_data_int3 = {data};
5181 globaldata[label].type = HELIOS_TYPE_INT3;
5182 } else if constexpr (std::is_same_v<T, int4>) {
5183 globaldata[label].global_data_int4 = {data};
5184 globaldata[label].type = HELIOS_TYPE_INT4;
5185 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
5186 globaldata[label].global_data_string = {data};
5187 globaldata[label].type = HELIOS_TYPE_STRING;
5188 } else if constexpr (std::is_same_v<T, bool>) {
5189 globaldata[label].global_data_bool = {data};
5190 globaldata[label].type = HELIOS_TYPE_BOOL;
5191 }
5192 globaldata[label].version++;
5193 }
5194
5196
5200 template<typename T>
5201 void setGlobalData(const char *label, const std::vector<T> &data) {
5202 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5203 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *> || std::is_same_v<T, bool>,
5204 "Context::setGlobalData() was called with an unsupported type.");
5205
5206 globaldata[label].size = data.size();
5207 if constexpr (std::is_same_v<T, int>) {
5208 globaldata[label].global_data_int = data;
5209 globaldata[label].type = HELIOS_TYPE_INT;
5210 } else if constexpr (std::is_same_v<T, uint>) {
5211 globaldata[label].global_data_uint = data;
5212 globaldata[label].type = HELIOS_TYPE_UINT;
5213 } else if constexpr (std::is_same_v<T, float>) {
5214 globaldata[label].global_data_float = data;
5215 globaldata[label].type = HELIOS_TYPE_FLOAT;
5216 } else if constexpr (std::is_same_v<T, double>) {
5217 globaldata[label].global_data_double = data;
5218 globaldata[label].type = HELIOS_TYPE_DOUBLE;
5219 } else if constexpr (std::is_same_v<T, vec2>) {
5220 globaldata[label].global_data_vec2 = data;
5221 globaldata[label].type = HELIOS_TYPE_VEC2;
5222 } else if constexpr (std::is_same_v<T, vec3>) {
5223 globaldata[label].global_data_vec3 = data;
5224 globaldata[label].type = HELIOS_TYPE_VEC3;
5225 } else if constexpr (std::is_same_v<T, vec4>) {
5226 globaldata[label].global_data_vec4 = data;
5227 globaldata[label].type = HELIOS_TYPE_VEC4;
5228 } else if constexpr (std::is_same_v<T, int2>) {
5229 globaldata[label].global_data_int2 = data;
5230 globaldata[label].type = HELIOS_TYPE_INT2;
5231 } else if constexpr (std::is_same_v<T, int3>) {
5232 globaldata[label].global_data_int3 = data;
5233 globaldata[label].type = HELIOS_TYPE_INT3;
5234 } else if constexpr (std::is_same_v<T, int4>) {
5235 globaldata[label].global_data_int4 = data;
5236 globaldata[label].type = HELIOS_TYPE_INT4;
5237 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
5238 globaldata[label].global_data_string = data;
5239 globaldata[label].type = HELIOS_TYPE_STRING;
5240 } else if constexpr (std::is_same_v<T, bool>) {
5241 globaldata[label].global_data_bool = data;
5242 globaldata[label].type = HELIOS_TYPE_BOOL;
5243 }
5244 globaldata[label].version++;
5245 }
5246
5248
5252 template<typename T>
5253 void getGlobalData(const char *label, T &data) const {
5254 // Use SFINAE to detect if T is std::vector<U> for some U
5255 if constexpr (std::is_same_v<T, std::vector<int>>) {
5256 // Vector case for int
5257 if (globaldata.at(label).type == HELIOS_TYPE_INT) {
5258 data = globaldata.at(label).global_data_int;
5259 } else {
5260 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) + " does not have type int.");
5261 }
5262 } else if constexpr (std::is_same_v<T, std::vector<uint>>) {
5263 // Vector case for uint
5264 if (globaldata.at(label).type == HELIOS_TYPE_UINT) {
5265 data = globaldata.at(label).global_data_uint;
5266 } else {
5267 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) + " does not have type uint.");
5268 }
5269 } else if constexpr (std::is_same_v<T, std::vector<float>>) {
5270 // Vector case for float
5271 if (globaldata.at(label).type == HELIOS_TYPE_FLOAT) {
5272 data = globaldata.at(label).global_data_float;
5273 } else {
5274 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) + " does not have type float.");
5275 }
5276 } else if constexpr (std::is_same_v<T, std::vector<double>>) {
5277 // Vector case for double
5278 if (globaldata.at(label).type == HELIOS_TYPE_DOUBLE) {
5279 data = globaldata.at(label).global_data_double;
5280 } else {
5281 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) + " does not have type double.");
5282 }
5283 } else if constexpr (std::is_same_v<T, std::vector<vec2>>) {
5284 // Vector case for vec2
5285 if (globaldata.at(label).type == HELIOS_TYPE_VEC2) {
5286 data = globaldata.at(label).global_data_vec2;
5287 } else {
5288 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) + " does not have type vec2.");
5289 }
5290 } else if constexpr (std::is_same_v<T, std::vector<vec3>>) {
5291 // Vector case for vec3
5292 if (globaldata.at(label).type == HELIOS_TYPE_VEC3) {
5293 data = globaldata.at(label).global_data_vec3;
5294 } else {
5295 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) + " does not have type vec3.");
5296 }
5297 } else if constexpr (std::is_same_v<T, std::vector<vec4>>) {
5298 // Vector case for vec4
5299 if (globaldata.at(label).type == HELIOS_TYPE_VEC4) {
5300 data = globaldata.at(label).global_data_vec4;
5301 } else {
5302 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) + " does not have type vec4.");
5303 }
5304 } else if constexpr (std::is_same_v<T, std::vector<int2>>) {
5305 // Vector case for int2
5306 if (globaldata.at(label).type == HELIOS_TYPE_INT2) {
5307 data = globaldata.at(label).global_data_int2;
5308 } else {
5309 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) + " does not have type int2.");
5310 }
5311 } else if constexpr (std::is_same_v<T, std::vector<int3>>) {
5312 // Vector case for int3
5313 if (globaldata.at(label).type == HELIOS_TYPE_INT3) {
5314 data = globaldata.at(label).global_data_int3;
5315 } else {
5316 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) + " does not have type int3.");
5317 }
5318 } else if constexpr (std::is_same_v<T, std::vector<int4>>) {
5319 // Vector case for int4
5320 if (globaldata.at(label).type == HELIOS_TYPE_INT4) {
5321 data = globaldata.at(label).global_data_int4;
5322 } else {
5323 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) + " does not have type int4.");
5324 }
5325 } else if constexpr (std::is_same_v<T, std::vector<std::string>>) {
5326 // Vector case for string
5327 if (globaldata.at(label).type == HELIOS_TYPE_STRING) {
5328 data = globaldata.at(label).global_data_string;
5329 } else {
5330 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) + " does not have type string.");
5331 }
5332 } else if constexpr (std::is_same_v<T, int>) {
5333 // Scalar case for int
5334 if (globaldata.at(label).type == HELIOS_TYPE_INT) {
5335 data = globaldata.at(label).global_data_int.front();
5336 } else {
5337 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) + " does not have type int.");
5338 }
5339 } else if constexpr (std::is_same_v<T, uint>) {
5340 // Scalar case for uint
5341 if (globaldata.at(label).type == HELIOS_TYPE_UINT) {
5342 data = globaldata.at(label).global_data_uint.front();
5343 } else {
5344 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) + " does not have type uint.");
5345 }
5346 } else if constexpr (std::is_same_v<T, float>) {
5347 // Scalar case for float
5348 if (globaldata.at(label).type == HELIOS_TYPE_FLOAT) {
5349 data = globaldata.at(label).global_data_float.front();
5350 } else {
5351 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) + " does not have type float.");
5352 }
5353 } else if constexpr (std::is_same_v<T, double>) {
5354 // Scalar case for double
5355 if (globaldata.at(label).type == HELIOS_TYPE_DOUBLE) {
5356 data = globaldata.at(label).global_data_double.front();
5357 } else {
5358 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) + " does not have type double.");
5359 }
5360 } else if constexpr (std::is_same_v<T, vec2>) {
5361 // Scalar case for vec2
5362 if (globaldata.at(label).type == HELIOS_TYPE_VEC2) {
5363 data = globaldata.at(label).global_data_vec2.front();
5364 } else {
5365 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) + " does not have type vec2.");
5366 }
5367 } else if constexpr (std::is_same_v<T, vec3>) {
5368 // Scalar case for vec3
5369 if (globaldata.at(label).type == HELIOS_TYPE_VEC3) {
5370 data = globaldata.at(label).global_data_vec3.front();
5371 } else {
5372 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) + " does not have type vec3.");
5373 }
5374 } else if constexpr (std::is_same_v<T, vec4>) {
5375 // Scalar case for vec4
5376 if (globaldata.at(label).type == HELIOS_TYPE_VEC4) {
5377 data = globaldata.at(label).global_data_vec4.front();
5378 } else {
5379 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) + " does not have type vec4.");
5380 }
5381 } else if constexpr (std::is_same_v<T, int2>) {
5382 // Scalar case for int2
5383 if (globaldata.at(label).type == HELIOS_TYPE_INT2) {
5384 data = globaldata.at(label).global_data_int2.front();
5385 } else {
5386 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) + " does not have type int2.");
5387 }
5388 } else if constexpr (std::is_same_v<T, int3>) {
5389 // Scalar case for int3
5390 if (globaldata.at(label).type == HELIOS_TYPE_INT3) {
5391 data = globaldata.at(label).global_data_int3.front();
5392 } else {
5393 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) + " does not have type int3.");
5394 }
5395 } else if constexpr (std::is_same_v<T, int4>) {
5396 // Scalar case for int4
5397 if (globaldata.at(label).type == HELIOS_TYPE_INT4) {
5398 data = globaldata.at(label).global_data_int4.front();
5399 } else {
5400 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) + " does not have type int4.");
5401 }
5402 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
5403 // Scalar case for string
5404 if (globaldata.at(label).type == HELIOS_TYPE_STRING) {
5405 data = globaldata.at(label).global_data_string.front();
5406 } else {
5407 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) + " does not have type string.");
5408 }
5409 } else if constexpr (std::is_same_v<T, bool>) {
5410 // Scalar case for bool
5411 if (globaldata.at(label).type == HELIOS_TYPE_BOOL) {
5412 data = globaldata.at(label).global_data_bool.front();
5413 } else {
5414 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type bool, but data " + std::string(label) + " does not have type bool.");
5415 }
5416 } else {
5417 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5418 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *> ||
5419 std::is_same_v<T, std::vector<int>> || std::is_same_v<T, std::vector<uint>> || std::is_same_v<T, std::vector<float>> || std::is_same_v<T, std::vector<double>> || std::is_same_v<T, std::vector<vec2>> ||
5420 std::is_same_v<T, std::vector<vec3>> || std::is_same_v<T, std::vector<vec4>> || std::is_same_v<T, std::vector<int2>> || std::is_same_v<T, std::vector<int3>> || std::is_same_v<T, std::vector<int4>> ||
5421 std::is_same_v<T, std::vector<std::string>> || std::is_same_v<T, std::vector<bool>>,
5422 "CompoundObject::getGlobalData() was called with an unsupported type.");
5423 }
5424 }
5425
5427
5431 void renameGlobalData(const char *old_label, const char *new_label);
5432
5434
5438 void duplicateGlobalData(const char *old_label, const char *new_label);
5439
5441
5444 void clearGlobalData(const char *label);
5445
5447
5451 HeliosDataType getGlobalDataType(const char *label) const;
5452
5454
5458 size_t getGlobalDataSize(const char *label) const;
5459
5461
5466 uint64_t getGlobalDataVersion(const char *label) const;
5467
5469
5472 [[nodiscard]] std::vector<std::string> listGlobalData() const;
5473
5475
5479 bool doesGlobalDataExist(const char *label) const;
5480
5482
5487 void incrementGlobalData(const char *label, int increment);
5488
5490
5495 void incrementGlobalData(const char *label, uint increment);
5496
5498
5503 void incrementGlobalData(const char *label, float increment);
5504
5506
5511 void incrementGlobalData(const char *label, double increment);
5512
5513 //--------- Compound Objects Methods -------------//
5514
5516
5519 [[nodiscard]] uint getObjectCount() const;
5520
5522
5525 [[nodiscard]] bool doesObjectExist(uint ObjID) const;
5526
5528
5531 [[nodiscard]] std::vector<uint> getAllObjectIDs() const;
5532
5534
5537 void deleteObject(uint ObjID);
5538
5540
5543 void deleteObject(const std::vector<uint> &ObjIDs);
5544
5546
5550 uint copyObject(uint ObjID);
5551
5553
5557 std::vector<uint> copyObject(const std::vector<uint> &ObjIDs);
5558
5560
5564 void copyObjectData(uint source_objID, uint destination_objID);
5565
5567
5572 void duplicateObjectData(uint objID, const char *old_label, const char *new_label);
5573
5575
5580 void renameObjectData(uint objID, const char *old_label, const char *new_label);
5581
5583
5589 std::vector<uint> filterObjectsByData(const std::vector<uint> &ObjIDs, const char *object_data, float threshold, const char *comparator) const;
5590
5592
5596 void translateObject(uint ObjID, const vec3 &shift) const;
5597
5599
5603 void translateObject(const std::vector<uint> &ObjIDs, const vec3 &shift) const;
5604
5606
5611 void rotateObject(uint ObjID, float rotation_radians, const char *rotation_axis_xyz) const;
5612
5614
5619 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const char *rotation_axis_xyz) const;
5620
5622
5627 void rotateObject(uint ObjID, float rotation_radians, const vec3 &rotation_axis_vector) const;
5628
5630
5635 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_axis_vector) const;
5636
5638
5644 void rotateObject(uint ObjID, float rotation_radians, const vec3 &rotation_origin, const vec3 &rotation_axis_vector) const;
5645
5647
5653 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_origin, const vec3 &rotation_axis_vector) const;
5654
5656
5661 void rotateObjectAboutOrigin(uint ObjID, float rotation_radians, const vec3 &rotation_axis_vector) const;
5662
5664
5669 void rotateObjectAboutOrigin(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_axis_vector) const;
5670
5672
5676 void scaleObject(uint ObjID, const helios::vec3 &scalefact) const;
5677
5679
5683 void scaleObject(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
5684
5686
5690 void scaleObjectAboutCenter(uint ObjID, const helios::vec3 &scalefact) const;
5691
5693
5697 void scaleObjectAboutCenter(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
5698
5700
5705 void scaleObjectAboutPoint(uint ObjID, const helios::vec3 &scalefact, const helios::vec3 &point) const;
5706
5708
5713 void scaleObjectAboutPoint(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact, const helios::vec3 &point) const;
5714
5716
5721 void scaleObjectAboutOrigin(uint ObjID, const helios::vec3 &scalefact) const;
5722
5724
5729 void scaleObjectAboutOrigin(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
5730
5732
5735 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(uint ObjID) const;
5736
5738
5741 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(const std::vector<uint> &ObjIDs) const;
5742
5744
5747 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(const std::vector<std::vector<uint>> &ObjIDs) const;
5748
5750
5753 [[nodiscard]] helios::ObjectType getObjectType(uint ObjID) const;
5754
5756
5759 [[nodiscard]] float getTileObjectAreaRatio(uint ObjID) const;
5760
5762
5765 [[nodiscard]] std::vector<float> getTileObjectAreaRatio(const std::vector<uint> &ObjIDs) const;
5766
5768
5772 void setTileObjectSubdivisionCount(const std::vector<uint> &ObjIDs, const int2 &new_subdiv);
5773
5775
5779 void setTileObjectSubdivisionCount(const std::vector<uint> &ObjIDs, float area_ratio);
5780
5782
5787 [[nodiscard]] helios::vec3 getTileObjectCenter(uint ObjID) const;
5788
5790
5793 [[nodiscard]] helios::vec2 getTileObjectSize(uint ObjID) const;
5794
5796
5799 [[nodiscard]] helios::int2 getTileObjectSubdivisionCount(uint ObjID) const;
5800
5802
5805 [[nodiscard]] helios::vec3 getTileObjectNormal(uint ObjID) const;
5806
5808
5811 [[nodiscard]] std::vector<helios::vec2> getTileObjectTextureUV(uint ObjID) const;
5812
5814
5817 [[nodiscard]] std::vector<helios::vec3> getTileObjectVertices(uint ObjID) const;
5818
5820
5823 [[nodiscard]] helios::vec3 getSphereObjectCenter(uint ObjID) const;
5824
5826
5829 [[nodiscard]] helios::vec3 getSphereObjectRadius(uint ObjID) const;
5830
5832
5835 [[nodiscard]] uint getSphereObjectSubdivisionCount(uint ObjID) const;
5836
5838
5841 [[nodiscard]] float getSphereObjectVolume(uint ObjID) const;
5842
5844
5847 [[nodiscard]] uint getTubeObjectSubdivisionCount(uint ObjID) const;
5848
5850
5853 [[nodiscard]] std::vector<helios::vec3> getTubeObjectNodes(uint ObjID) const;
5854
5856
5859 [[nodiscard]] uint getTubeObjectNodeCount(uint ObjID) const;
5860
5862
5865 [[nodiscard]] std::vector<float> getTubeObjectNodeRadii(uint ObjID) const;
5866
5868
5871 [[nodiscard]] std::vector<RGBcolor> getTubeObjectNodeColors(uint ObjID) const;
5872
5874
5877 [[nodiscard]] float getTubeObjectVolume(uint ObjID) const;
5878
5880
5884 [[nodiscard]] float getTubeObjectSegmentVolume(uint ObjID, uint segment_index) const;
5885
5887
5893 void appendTubeSegment(uint ObjID, const helios::vec3 &node_position, float radius, const RGBcolor &color);
5894
5896
5903 void appendTubeSegment(uint ObjID, const helios::vec3 &node_position, float node_radius, const char *texturefile, const helios::vec2 &textureuv_ufrac);
5904
5906
5910 void scaleTubeGirth(uint ObjID, float scale_factor);
5911
5913
5917 void setTubeRadii(uint ObjID, const std::vector<float> &node_radii);
5918
5920
5924 void scaleTubeLength(uint ObjID, float scale_factor);
5925
5927
5931 void pruneTubeNodes(uint ObjID, uint node_index);
5932
5934
5938 void setTubeNodes(uint ObjID, const std::vector<helios::vec3> &node_xyz);
5939
5941
5944 [[nodiscard]] helios::vec3 getBoxObjectCenter(uint ObjID) const;
5945
5947
5950 [[nodiscard]] helios::vec3 getBoxObjectSize(uint ObjID) const;
5951
5953
5956 [[nodiscard]] helios::int3 getBoxObjectSubdivisionCount(uint ObjID) const;
5957
5959
5962 [[nodiscard]] float getBoxObjectVolume(uint ObjID) const;
5963
5965
5968 [[nodiscard]] helios::vec3 getDiskObjectCenter(uint ObjID) const;
5969
5971
5974 [[nodiscard]] helios::vec2 getDiskObjectSize(uint ObjID) const;
5975
5977
5980 [[nodiscard]] uint getDiskObjectSubdivisionCount(uint ObjID) const;
5981
5983
5986 [[nodiscard]] float getPolymeshObjectVolume(uint ObjID) const;
5987
5989
5992 [[nodiscard]] uint getConeObjectSubdivisionCount(uint ObjID) const;
5993
5995
5998 [[nodiscard]] std::vector<helios::vec3> getConeObjectNodes(uint ObjID) const;
5999
6001
6004 [[nodiscard]] std::vector<float> getConeObjectNodeRadii(uint ObjID) const;
6005
6007
6011 [[nodiscard]] helios::vec3 getConeObjectNode(uint ObjID, int number) const;
6012
6014
6018 [[nodiscard]] float getConeObjectNodeRadius(uint ObjID, int number) const;
6019
6021
6024 [[nodiscard]] helios::vec3 getConeObjectAxisUnitVector(uint ObjID) const;
6025
6027
6031 [[nodiscard]] float getConeObjectLength(uint ObjID) const;
6032
6034
6037 [[nodiscard]] float getConeObjectVolume(uint ObjID) const;
6038
6040
6044 void scaleConeObjectLength(uint ObjID, float scale_factor);
6045
6047
6051 void scaleConeObjectGirth(uint ObjID, float scale_factor);
6052
6054
6063 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv);
6064
6066
6075 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const RGBcolor &color);
6076
6078
6087 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile);
6088
6090
6100 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile, const int2 &texture_repeat);
6101
6103
6111 uint addSphereObject(uint Ndivs, const vec3 &center, float radius);
6112
6114
6122 uint addSphereObject(uint Ndivs, const vec3 &center, float radius, const RGBcolor &color);
6123
6125
6133 uint addSphereObject(uint Ndivs, const vec3 &center, float radius, const char *texturefile);
6134
6136
6144 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius);
6145
6147
6155 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius, const RGBcolor &color);
6156
6158
6166 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius, const char *texturefile);
6167
6169
6178 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius);
6179
6181
6190 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const std::vector<RGBcolor> &color);
6191
6193
6203 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile);
6204
6206
6217 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile, const std::vector<float> &textureuv_ufrac);
6218
6220
6229 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv);
6230
6232
6241 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color);
6242
6244
6253 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile);
6254
6256
6266 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color, bool reverse_normals);
6267
6269
6279 uint addBoxObject(vec3 center, const vec3 &size, const int3 &subdiv, const char *texturefile, bool reverse_normals);
6280
6282
6291 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size);
6292
6294
6303 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
6304
6306
6315 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6316
6318
6327 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6328
6330
6340 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
6341
6343
6352 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6353
6355
6364 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6365
6367
6377 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texturefile);
6378
6380
6385 uint addPolymeshObject(const std::vector<uint> &UUIDs);
6386
6388
6399 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1);
6400
6402
6413 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const RGBcolor &color);
6414
6416
6427 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const char *texturefile);
6428
6430
6438 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius);
6439
6441
6449 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius, const RGBcolor &color);
6450
6452
6460 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius, const char *texturefile);
6461
6463
6472 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv);
6473
6475
6484 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const RGBcolor &color);
6485
6487
6496 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile);
6497
6499
6509 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile, const int2 &texture_repeat);
6510
6512
6521 std::vector<uint> addTube(uint Ndivs, const std::vector<vec3> &nodes, const std::vector<float> &radius);
6522
6524
6533 std::vector<uint> addTube(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const std::vector<RGBcolor> &color);
6534
6536
6545 std::vector<uint> addTube(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile);
6546
6548
6557 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv);
6558
6560
6569 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color);
6570
6572
6581 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile);
6582
6584
6594 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color, bool reverse_normals);
6595
6597
6607 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile, bool reverse_normals);
6608
6610
6619 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size);
6620
6622
6631 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
6632
6634
6643 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6644
6646
6655 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6656
6658
6668 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
6669
6671
6680 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6681
6683
6692 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6693
6695
6705 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texturefile);
6706
6708
6718 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1);
6719
6721
6731 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, RGBcolor &color);
6732
6734
6744 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const char *texturefile);
6745
6747
6754 void addTimeseriesData(const char *label, float value, const Date &date, const Time &time);
6755
6757
6765 void updateTimeseriesData(const char *label, const Date &date, const Time &time, float new_value);
6766
6768
6773 void setCurrentTimeseriesPoint(const char *label, uint index);
6774
6776
6783 float queryTimeseriesData(const char *label, const Date &date, const Time &time) const;
6784
6786
6791 float queryTimeseriesData(const char *label) const;
6792
6794
6800 float queryTimeseriesData(const char *label, uint index) const;
6801
6803
6809 Time queryTimeseriesTime(const char *label, uint index) const;
6810
6812
6818 Date queryTimeseriesDate(const char *label, uint index) const;
6819
6821
6825 uint getTimeseriesLength(const char *label) const;
6826
6828
6832 bool doesTimeseriesVariableExist(const char *label) const;
6833
6835 [[nodiscard]] std::vector<std::string> listTimeseriesVariables() const;
6836
6838
6839 void clearTimeseriesData();
6840
6842
6847 void deleteTimeseriesVariable(const char *label);
6848
6850
6875 void loadTabularTimeseriesData(const std::string &data_file, const std::vector<std::string> &column_labels, const std::string &delimiter, const std::string &date_string_format = "YYYYMMDD", uint headerlines = 0);
6876
6878
6883 void getDomainBoundingBox(helios::vec2 &xbounds, helios::vec2 &ybounds, helios::vec2 &zbounds) const;
6884
6886
6892 void getDomainBoundingBox(const std::vector<uint> &UUIDs, helios::vec2 &xbounds, helios::vec2 &ybounds, helios::vec2 &zbounds) const;
6893
6895
6899 void getDomainBoundingSphere(helios::vec3 &center, float &radius) const;
6900
6902
6907 void getDomainBoundingSphere(const std::vector<uint> &UUIDs, helios::vec3 &center, float &radius) const;
6908
6910
6913 void cropDomainX(const vec2 &xbounds);
6914
6916
6919 void cropDomainY(const vec2 &ybounds);
6920
6922
6925 void cropDomainZ(const vec2 &zbounds);
6926
6928
6934 void cropDomain(std::vector<uint> &UUIDs, const vec2 &xbounds, const vec2 &ybounds, const vec2 &zbounds);
6935
6937
6942 void cropDomain(const vec2 &xbounds, const vec2 &ybounds, const vec2 &zbounds);
6943
6945
6951 void colorPrimitiveByDataPseudocolor(const std::vector<uint> &UUIDs, const std::string &primitive_data, const std::string &colormap, uint Ncolors);
6952
6954
6962 void colorPrimitiveByDataPseudocolor(const std::vector<uint> &UUIDs, const std::string &primitive_data, const std::string &colormap, uint Ncolors, float data_min, float data_max);
6963
6965
6971 std::vector<uint> loadXML(const char *filename, bool quiet = false);
6972
6974
6977 [[nodiscard]] std::vector<std::string> getLoadedXMLFiles();
6978
6980
6986 static bool scanXMLForTag(const std::string &filename, const std::string &tag, const std::string &label = "");
6987
6989
6993 void writeXML(const char *filename, bool quiet = false) const;
6994
6996
7001 void writeXML(const char *filename, const std::vector<uint> &UUIDs, bool quiet = false) const;
7002
7004
7009 void writeXML_byobject(const char *filename, const std::vector<uint> &UUIDs, bool quiet = false) const;
7010
7012
7017 void writePrimitiveData(const std::string &filename, const std::vector<std::string> &column_format, bool print_header = false) const;
7018
7020
7026 void writePrimitiveData(const std::string &filename, const std::vector<std::string> &column_format, const std::vector<uint> &UUIDs, bool print_header = false) const;
7027
7029
7035 std::vector<uint> loadPLY(const char *filename, bool silent = false);
7036
7038
7047 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const std::string &upaxis = "YUP", bool silent = false);
7048
7050
7060 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const std::string &upaxis = "YUP", bool silent = false);
7061
7063
7072 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const RGBcolor &default_color, const std::string &upaxis = "YUP", bool silent = false);
7073
7075
7085 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const RGBcolor &default_color, const std::string &upaxis = "YUP", bool silent = false);
7086
7088
7091 void writePLY(const char *filename) const;
7092
7094
7098 void writePLY(const char *filename, const std::vector<uint> &UUIDs) const;
7099
7100 // Asset directory registration removed - now using HELIOS_BUILD resolution
7101
7103
7107 std::vector<uint> loadOBJ(const char *filename, bool silent = false);
7108
7110
7119 std::vector<uint> loadOBJ(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const RGBcolor &default_color, bool silent = false);
7120
7122
7132 std::vector<uint> loadOBJ(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const RGBcolor &default_color, const char *upaxis, bool silent = false);
7133
7134
7136
7146 std::vector<uint> loadOBJ(const char *filename, const vec3 &origin, const helios::vec3 &scale, const SphericalCoord &rotation, const RGBcolor &default_color, const char *upaxis, bool silent = false);
7147
7149
7154 void writeOBJ(const std::string &filename, bool write_normals = false, bool silent = false) const;
7155
7157
7163 void writeOBJ(const std::string &filename, const std::vector<uint> &UUIDs, bool write_normals = false, bool silent = false) const;
7164
7166
7173 void writeOBJ(const std::string &filename, const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_dat_fields, bool write_normals = false, bool silent = false) const;
7174
7175 //------------ FILE PATH RESOLUTION ----------------//
7176
7178
7183 std::filesystem::path resolveFilePath(const std::string &filename) const;
7184
7186
7192 void setDate(int day, int month, int year);
7193
7195
7199 void setDate(const Date &date);
7200
7202
7207 void setDate(int Julian_day, int year);
7208
7210
7214 [[nodiscard]] helios::Date getDate() const;
7215
7217
7221 [[nodiscard]] const char *getMonthString() const;
7222
7224
7228 [[nodiscard]] int getJulianDate() const;
7229
7231
7237 void setTime(int minute, int hour);
7238
7240
7247 void setTime(int second, int minute, int hour);
7248
7250
7255 void setTime(const Time &time);
7256
7258
7262 [[nodiscard]] helios::Time getTime() const;
7263
7265
7268 void setLocation(const helios::Location &location);
7269
7271
7274 [[nodiscard]] helios::Location getLocation() const;
7275
7277
7280 float randu();
7281
7283
7288 float randu(float min, float max);
7289
7291
7296 int randu(int min, int max);
7297
7299
7302 float randn();
7303
7305
7310 float randn(float mean, float stddev);
7311
7313
7317 void duplicatePrimitiveData(const char *existing_data_label, const char *copy_data_label);
7318
7320
7325 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, float &mean) const;
7326
7328
7333 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, double &mean) const;
7334
7336
7341 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &mean) const;
7342
7344
7349 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &mean) const;
7350
7352
7357 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &mean) const;
7358
7360
7365 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, float &awt_mean) const;
7366
7368
7373 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, double &awt_mean) const;
7374
7376
7381 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &awt_mean) const;
7382
7384
7389 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &awt_mean) const;
7390
7392
7397 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &awt_mean) const;
7398
7400
7405 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, float &sum) const;
7406
7408
7413 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, double &sum) const;
7414
7416
7421 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &sum) const;
7422
7424
7429 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &sum) const;
7430
7432
7437 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &sum) const;
7438
7440
7445 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, float &awt_sum) const;
7446
7448
7453 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, double &sum) const;
7454
7456
7461 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &sum) const;
7462
7464
7469 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &sum) const;
7470
7472
7477 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &sum) const;
7478
7480
7486 void scalePrimitiveData(const std::vector<uint> &UUIDs, const std::string &label, float scaling_factor);
7487
7489
7494 void scalePrimitiveData(const std::string &label, float scaling_factor);
7495
7497
7503 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, int increment);
7504
7506
7512 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, uint increment);
7513
7515
7521 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, float increment);
7522
7524
7530 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, double increment);
7531
7533
7539 void aggregatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label);
7540
7542
7548 void aggregatePrimitiveDataProduct(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label);
7549
7551
7555 [[nodiscard]] float sumPrimitiveSurfaceArea(const std::vector<uint> &UUIDs) const;
7556
7558
7566 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, float filter_value, const std::string &comparator) const;
7567
7569
7577 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, double filter_value, const std::string &comparator) const;
7578
7580
7588 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, int filter_value, const std::string &comparator) const;
7589
7591
7599 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, uint filter_value, const std::string &comparator) const;
7600
7602
7609 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, const std::string &filter_value) const;
7610
7612
7620 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, float filter_value, const std::string &comparator) const;
7621
7623
7631 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, double filter_value, const std::string &comparator) const;
7632
7634
7642 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, int filter_value, const std::string &comparator) const;
7643
7645
7653 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, uint filter_value, const std::string &comparator) const;
7654
7656
7663 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, const std::string &filter_value) const;
7664
7666
7676 std::vector<std::string> generateTexturesFromColormap(const std::string &texturefile, const std::vector<RGBcolor> &colormap_data);
7677
7679
7684 std::vector<RGBcolor> generateColormap(const std::string &colormap, uint Ncolors);
7685
7687
7694 std::vector<RGBcolor> generateColormap(const std::vector<helios::RGBcolor> &ctable, const std::vector<float> &cfrac, uint Ncolors);
7695
7696 // ---------- Template method implementations for data type consistency ---------- //
7697
7698 template<typename T>
7699 void storeDataWithTypeCasting(uint UUID, const char *label, const T &data, HeliosDataType target_type) {
7700 // Only cast between numeric scalar types
7701 if constexpr (std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double>) {
7702 if (target_type == HELIOS_TYPE_INT) {
7703 primitives.at(UUID)->setPrimitiveData(label, static_cast<int>(data));
7704 } else if (target_type == HELIOS_TYPE_UINT) {
7705 primitives.at(UUID)->setPrimitiveData(label, static_cast<uint>(data));
7706 } else if (target_type == HELIOS_TYPE_FLOAT) {
7707 primitives.at(UUID)->setPrimitiveData(label, static_cast<float>(data));
7708 } else if (target_type == HELIOS_TYPE_DOUBLE) {
7709 primitives.at(UUID)->setPrimitiveData(label, static_cast<double>(data));
7710 } else {
7711 // Fallback: store as original type
7712 primitives.at(UUID)->setPrimitiveData(label, data);
7713 }
7714 } else {
7715 // For non-numeric types, store as-is
7716 primitives.at(UUID)->setPrimitiveData(label, data);
7717 }
7718 }
7719
7720 template<typename T>
7721 void storeObjectDataWithTypeCasting(uint objID, const char *label, const T &data, HeliosDataType target_type) {
7722 // Only cast between numeric scalar types
7723 if constexpr (std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double>) {
7724 if (target_type == HELIOS_TYPE_INT) {
7725 objects.at(objID)->setObjectData(label, static_cast<int>(data));
7726 } else if (target_type == HELIOS_TYPE_UINT) {
7727 objects.at(objID)->setObjectData(label, static_cast<uint>(data));
7728 } else if (target_type == HELIOS_TYPE_FLOAT) {
7729 objects.at(objID)->setObjectData(label, static_cast<float>(data));
7730 } else if (target_type == HELIOS_TYPE_DOUBLE) {
7731 objects.at(objID)->setObjectData(label, static_cast<double>(data));
7732 } else {
7733 // Fallback: store as original type
7734 objects.at(objID)->setObjectData(label, data);
7735 }
7736 } else {
7737 // For non-numeric types, store as-is
7738 objects.at(objID)->setObjectData(label, data);
7739 }
7740 }
7741
7742 template<typename T>
7743 HeliosDataType registerOrValidatePrimitiveDataType(const std::string &label, HeliosDataType data_type) {
7744 auto it = primitive_data_type_registry.find(label);
7745 if (it == primitive_data_type_registry.end()) {
7746 // First time this label is used - register the type
7747 primitive_data_type_registry[label] = data_type;
7748 return data_type;
7749 } else {
7750 // Label exists - check for type consistency
7751 HeliosDataType expected_type = it->second;
7752 if (expected_type != data_type) {
7753 // Types don't match - check if casting is possible
7754 if (!isTypeCastingSupported(data_type, expected_type)) {
7755 helios_runtime_error("ERROR (Context::registerOrValidatePrimitiveDataType): Data type mismatch for label '" + label + "'. Expected " + dataTypeToString(expected_type) + " but got " + dataTypeToString(data_type) +
7756 ". Type casting between these types is not supported.");
7757 } else {
7758 std::cerr << "WARNING (Context::registerOrValidatePrimitiveDataType): Type casting from " + dataTypeToString(data_type) + " to " + dataTypeToString(expected_type) + " for label '" + label +
7759 "'. Consider using consistent types."
7760 << std::endl;
7761 }
7762 }
7763 return expected_type;
7764 }
7765 }
7766
7767 template<typename T>
7768 HeliosDataType registerOrValidateObjectDataType(const std::string &label, HeliosDataType data_type) {
7769 auto it = object_data_type_registry.find(label);
7770 if (it == object_data_type_registry.end()) {
7771 // First time this label is used - register the type
7772 object_data_type_registry[label] = data_type;
7773 return data_type;
7774 } else {
7775 // Label exists - check for type consistency
7776 HeliosDataType expected_type = it->second;
7777 if (expected_type != data_type) {
7778 // Types don't match - check if casting is possible
7779 if (!isTypeCastingSupported(data_type, expected_type)) {
7780 helios_runtime_error("ERROR (Context::registerOrValidateObjectDataType): Data type mismatch for label '" + label + "'. Expected " + dataTypeToString(expected_type) + " but got " + dataTypeToString(data_type) +
7781 ". Type casting between these types is not supported.");
7782 } else {
7783 std::cerr << "WARNING (Context::registerOrValidateObjectDataType): Type casting from " + dataTypeToString(data_type) + " to " + dataTypeToString(expected_type) + " for label '" + label + "'. Consider using consistent types."
7784 << std::endl;
7785 }
7786 }
7787 return expected_type;
7788 }
7789 }
7790
7791 //----------- TEMPLATE METHOD IMPLEMENTATIONS FOR VALUE REGISTRY ----------//
7792
7794 template<typename T>
7795 void incrementPrimitiveValueRegistry(const std::string &label, const T &value) {
7796 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
7797 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7798 primitive_string_value_registry[label][string_value]++;
7799 } else if constexpr (std::is_same_v<T, int>) {
7800 primitive_int_value_registry[label][value]++;
7801 } else if constexpr (std::is_same_v<T, uint>) {
7802 primitive_uint_value_registry[label][value]++;
7803 }
7804 }
7805
7807 template<typename T>
7808 void decrementPrimitiveValueRegistry(const std::string &label, const T &value) {
7809 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
7810 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7811 auto label_it = primitive_string_value_registry.find(label);
7812 if (label_it != primitive_string_value_registry.end()) {
7813 auto value_it = label_it->second.find(string_value);
7814 if (value_it != label_it->second.end() && value_it->second > 0) {
7815 value_it->second--;
7816 if (value_it->second == 0) {
7817 label_it->second.erase(value_it);
7818 if (label_it->second.empty()) {
7819 primitive_string_value_registry.erase(label_it);
7820 }
7821 }
7822 }
7823 }
7824 } else if constexpr (std::is_same_v<T, int>) {
7825 auto label_it = primitive_int_value_registry.find(label);
7826 if (label_it != primitive_int_value_registry.end()) {
7827 auto value_it = label_it->second.find(value);
7828 if (value_it != label_it->second.end() && value_it->second > 0) {
7829 value_it->second--;
7830 if (value_it->second == 0) {
7831 label_it->second.erase(value_it);
7832 if (label_it->second.empty()) {
7833 primitive_int_value_registry.erase(label_it);
7834 }
7835 }
7836 }
7837 }
7838 } else if constexpr (std::is_same_v<T, uint>) {
7839 auto label_it = primitive_uint_value_registry.find(label);
7840 if (label_it != primitive_uint_value_registry.end()) {
7841 auto value_it = label_it->second.find(value);
7842 if (value_it != label_it->second.end() && value_it->second > 0) {
7843 value_it->second--;
7844 if (value_it->second == 0) {
7845 label_it->second.erase(value_it);
7846 if (label_it->second.empty()) {
7847 primitive_uint_value_registry.erase(label_it);
7848 }
7849 }
7850 }
7851 }
7852 }
7853 }
7854
7856 template<typename T>
7857 void incrementObjectValueRegistry(const std::string &label, const T &value) {
7858 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
7859 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7860 object_string_value_registry[label][string_value]++;
7861 } else if constexpr (std::is_same_v<T, int>) {
7862 object_int_value_registry[label][value]++;
7863 } else if constexpr (std::is_same_v<T, uint>) {
7864 object_uint_value_registry[label][value]++;
7865 }
7866 }
7867
7869 template<typename T>
7870 void decrementObjectValueRegistry(const std::string &label, const T &value) {
7871 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
7872 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7873 auto label_it = object_string_value_registry.find(label);
7874 if (label_it != object_string_value_registry.end()) {
7875 auto value_it = label_it->second.find(string_value);
7876 if (value_it != label_it->second.end() && value_it->second > 0) {
7877 value_it->second--;
7878 if (value_it->second == 0) {
7879 label_it->second.erase(value_it);
7880 if (label_it->second.empty()) {
7881 object_string_value_registry.erase(label_it);
7882 }
7883 }
7884 }
7885 }
7886 } else if constexpr (std::is_same_v<T, int>) {
7887 auto label_it = object_int_value_registry.find(label);
7888 if (label_it != object_int_value_registry.end()) {
7889 auto value_it = label_it->second.find(value);
7890 if (value_it != label_it->second.end() && value_it->second > 0) {
7891 value_it->second--;
7892 if (value_it->second == 0) {
7893 label_it->second.erase(value_it);
7894 if (label_it->second.empty()) {
7895 object_int_value_registry.erase(label_it);
7896 }
7897 }
7898 }
7899 }
7900 } else if constexpr (std::is_same_v<T, uint>) {
7901 auto label_it = object_uint_value_registry.find(label);
7902 if (label_it != object_uint_value_registry.end()) {
7903 auto value_it = label_it->second.find(value);
7904 if (value_it != label_it->second.end() && value_it->second > 0) {
7905 value_it->second--;
7906 if (value_it->second == 0) {
7907 label_it->second.erase(value_it);
7908 if (label_it->second.empty()) {
7909 object_uint_value_registry.erase(label_it);
7910 }
7911 }
7912 }
7913 }
7914 }
7915 }
7916
7917 //----------- UNIQUE VALUE QUERY METHODS ----------//
7918
7920
7926 template<typename T>
7927 void getUniquePrimitiveDataValues(const std::string &label, std::vector<T> &values) const {
7928 static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>, "getUniquePrimitiveDataValues() only supports std::string, int, and uint types.");
7929
7931 helios_runtime_error("ERROR (Context::getUniquePrimitiveDataValues): Value-level caching is not enabled for primitive data label '" + label + "'. Use enablePrimitiveDataValueCaching() first.");
7932 }
7933
7934 values.clear();
7935
7936 if constexpr (std::is_same_v<T, std::string>) {
7937 auto it = primitive_string_value_registry.find(label);
7938 if (it != primitive_string_value_registry.end()) {
7939 values.reserve(it->second.size());
7940 for (const auto &[value, count]: it->second) {
7941 if (count > 0) {
7942 values.push_back(value);
7943 }
7944 }
7945 }
7946 } else if constexpr (std::is_same_v<T, int>) {
7947 auto it = primitive_int_value_registry.find(label);
7948 if (it != primitive_int_value_registry.end()) {
7949 values.reserve(it->second.size());
7950 for (const auto &[value, count]: it->second) {
7951 if (count > 0) {
7952 values.push_back(value);
7953 }
7954 }
7955 }
7956 } else if constexpr (std::is_same_v<T, uint>) {
7957 auto it = primitive_uint_value_registry.find(label);
7958 if (it != primitive_uint_value_registry.end()) {
7959 values.reserve(it->second.size());
7960 for (const auto &[value, count]: it->second) {
7961 if (count > 0) {
7962 values.push_back(value);
7963 }
7964 }
7965 }
7966 }
7967 }
7968
7970
7976 template<typename T>
7977 void getUniqueObjectDataValues(const std::string &label, std::vector<T> &values) const {
7978 static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>, "getUniqueObjectDataValues() only supports std::string, int, and uint types.");
7979
7980 if (!isObjectDataValueCachingEnabled(label)) {
7981 helios_runtime_error("ERROR (Context::getUniqueObjectDataValues): Value-level caching is not enabled for object data label '" + label + "'. Use enableObjectDataValueCaching() first.");
7982 }
7983
7984 values.clear();
7985
7986 if constexpr (std::is_same_v<T, std::string>) {
7987 auto it = object_string_value_registry.find(label);
7988 if (it != object_string_value_registry.end()) {
7989 values.reserve(it->second.size());
7990 for (const auto &[value, count]: it->second) {
7991 if (count > 0) {
7992 values.push_back(value);
7993 }
7994 }
7995 }
7996 } else if constexpr (std::is_same_v<T, int>) {
7997 auto it = object_int_value_registry.find(label);
7998 if (it != object_int_value_registry.end()) {
7999 values.reserve(it->second.size());
8000 for (const auto &[value, count]: it->second) {
8001 if (count > 0) {
8002 values.push_back(value);
8003 }
8004 }
8005 }
8006 } else if constexpr (std::is_same_v<T, uint>) {
8007 auto it = object_uint_value_registry.find(label);
8008 if (it != object_uint_value_registry.end()) {
8009 values.reserve(it->second.size());
8010 for (const auto &[value, count]: it->second) {
8011 if (count > 0) {
8012 values.push_back(value);
8013 }
8014 }
8015 }
8016 }
8017 }
8018 };
8019
8020} // namespace helios
8021
8022
8023#endif