1.3.49
 
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 struct GlobalData {
122
124 std::vector<int> global_data_int;
126 std::vector<uint> global_data_uint;
128 std::vector<float> global_data_float;
130 std::vector<double> global_data_double;
132 std::vector<vec2> global_data_vec2;
134 std::vector<vec3> global_data_vec3;
136 std::vector<vec4> global_data_vec4;
138 std::vector<int2> global_data_int2;
140 std::vector<int3> global_data_int3;
142 std::vector<int4> global_data_int4;
144 std::vector<std::string> global_data_string;
146 std::vector<bool> global_data_bool;
147
149 size_t size;
152 };
153
154 //--------------------- GEOMETRIC PRIMITIVES -----------------------------------//
155
156
157 //---------- COMPOUND OBJECTS ----------------//
158
178
180 public:
182
185 virtual ~CompoundObject() = 0;
186
188 [[nodiscard]] uint getObjectID() const;
189
191 [[nodiscard]] helios::ObjectType getObjectType() const;
192
194 [[nodiscard]] uint getPrimitiveCount() const;
195
197 [[nodiscard]] std::vector<uint> getPrimitiveUUIDs() const;
198
200 [[nodiscard]] bool doesObjectContainPrimitive(uint UUID);
201
203 [[nodiscard]] helios::vec3 getObjectCenter() const;
204
206 [[nodiscard]] float getArea() const;
207
209
212 void setColor(const helios::RGBcolor &color);
213
215
218 void setColor(const helios::RGBAcolor &color);
219
222
225 void useTextureColor();
226
228 [[nodiscard]] bool hasTexture() const;
229
231 [[nodiscard]] std::string getTextureFile() const;
232
234
237 void translate(const helios::vec3 &shift);
238
240
244 void rotate(float rotation_radians, const char *rotation_axis_xyz_string);
245
247
251 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector);
252
254
259 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector);
260
262
265 void scale(const helios::vec3 &scale);
266
268
272
274
278 void scaleAboutPoint(const helios::vec3 &scale, const helios::vec3 &point);
279
281
284 void getTransformationMatrix(float (&T)[16]) const;
285
287
290 void setTransformationMatrix(float (&T)[16]);
291
293
296 void setPrimitiveUUIDs(const std::vector<uint> &UUIDs);
297
299
302 void deleteChildPrimitive(uint UUID);
303
305
308 void deleteChildPrimitive(const std::vector<uint> &UUIDs);
309
311
314 [[nodiscard]] bool arePrimitivesComplete() const;
315
316 //-------- Object Data Methods ---------- //
317
319
324 template<typename T>
325 void setObjectData(const char *label, const T &data) {
326
327 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> ||
328 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 *>,
329 "CompoundObject::setObjectData() was called with an unsupported type.");
330
331 if constexpr (std::is_same_v<T, int>) {
332 object_data_int[label] = {data};
333 object_data_types[label] = HELIOS_TYPE_INT;
334 } else if constexpr (std::is_same_v<T, uint>) {
335 object_data_uint[label] = {data};
336 object_data_types[label] = HELIOS_TYPE_UINT;
337 } else if constexpr (std::is_same_v<T, float>) {
338 object_data_float[label] = {data};
339 object_data_types[label] = HELIOS_TYPE_FLOAT;
340 } else if constexpr (std::is_same_v<T, double>) {
341 object_data_double[label] = {data};
342 object_data_types[label] = HELIOS_TYPE_DOUBLE;
343 } else if constexpr (std::is_same_v<T, vec2>) {
344 object_data_vec2[label] = {data};
345 object_data_types[label] = HELIOS_TYPE_VEC2;
346 } else if constexpr (std::is_same_v<T, vec3>) {
347 object_data_vec3[label] = {data};
348 object_data_types[label] = HELIOS_TYPE_VEC3;
349 } else if constexpr (std::is_same_v<T, vec4>) {
350 object_data_vec4[label] = {data};
351 object_data_types[label] = HELIOS_TYPE_VEC4;
352 } else if constexpr (std::is_same_v<T, int2>) {
353 object_data_int2[label] = {data};
354 object_data_types[label] = HELIOS_TYPE_INT2;
355 } else if constexpr (std::is_same_v<T, int3>) {
356 object_data_int3[label] = {data};
357 object_data_types[label] = HELIOS_TYPE_INT3;
358 } else if constexpr (std::is_same_v<T, int4>) {
359 object_data_int4[label] = {data};
360 object_data_types[label] = HELIOS_TYPE_INT4;
361 } 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 *>) {
362 object_data_string[label] = {data};
363 object_data_types[label] = HELIOS_TYPE_STRING;
364 }
365 }
366
368
373 template<typename T>
374 void setObjectData(const char *label, const std::vector<T> &data) {
375
376 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> ||
377 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 *>,
378 "CompoundObject::setObjectData() was called with an unsupported type.");
379
380 if constexpr (std::is_same_v<T, int>) {
381 object_data_int[label] = data;
382 object_data_types[label] = HELIOS_TYPE_INT;
383 } else if constexpr (std::is_same_v<T, uint>) {
384 object_data_uint[label] = data;
385 object_data_types[label] = HELIOS_TYPE_UINT;
386 } else if constexpr (std::is_same_v<T, float>) {
387 object_data_float[label] = data;
388 object_data_types[label] = HELIOS_TYPE_FLOAT;
389 } else if constexpr (std::is_same_v<T, double>) {
390 object_data_double[label] = data;
391 object_data_types[label] = HELIOS_TYPE_DOUBLE;
392 } else if constexpr (std::is_same_v<T, vec2>) {
393 object_data_vec2[label] = data;
394 object_data_types[label] = HELIOS_TYPE_VEC2;
395 } else if constexpr (std::is_same_v<T, vec3>) {
396 object_data_vec3[label] = data;
397 object_data_types[label] = HELIOS_TYPE_VEC3;
398 } else if constexpr (std::is_same_v<T, vec4>) {
399 object_data_vec4[label] = data;
400 object_data_types[label] = HELIOS_TYPE_VEC4;
401 } else if constexpr (std::is_same_v<T, int2>) {
402 object_data_int2[label] = data;
403 object_data_types[label] = HELIOS_TYPE_INT2;
404 } else if constexpr (std::is_same_v<T, int3>) {
405 object_data_int3[label] = data;
406 object_data_types[label] = HELIOS_TYPE_INT3;
407 } else if constexpr (std::is_same_v<T, int4>) {
408 object_data_int4[label] = data;
409 object_data_types[label] = HELIOS_TYPE_INT4;
410 } 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 *>) {
411 object_data_string[label] = data;
412 object_data_types[label] = HELIOS_TYPE_STRING;
413 }
414 }
415
417
421 template<typename T>
422 void getObjectData(const char *label, T &data) const {
423#ifdef HELIOS_DEBUG
424 if (!doesObjectDataExist(label)) {
425 helios_runtime_error("ERROR (CompoundObject::getObjectData): Object data " + std::string(label) + " does not exist for primitive " + std::to_string(OID));
426 }
427#endif
428
429 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> ||
430 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 *>,
431 "CompoundObject::getObjectData() was called with an unsupported type.");
432
433 HeliosDataType type = object_data_types.at(label);
434
435 if constexpr (std::is_same_v<T, int>) {
436 if (type == HELIOS_TYPE_INT) {
437 data = object_data_int.at(label).front();
438 } else {
439 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.");
440 }
441 } else if constexpr (std::is_same_v<T, uint>) {
442 if (type == HELIOS_TYPE_UINT) {
443 data = object_data_uint.at(label).front();
444 } else {
445 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.");
446 }
447 } else if constexpr (std::is_same_v<T, float>) {
448 if (type == HELIOS_TYPE_FLOAT) {
449 data = object_data_float.at(label).front();
450 } else {
451 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.");
452 }
453 } else if constexpr (std::is_same_v<T, double>) {
454 if (type == HELIOS_TYPE_DOUBLE) {
455 data = object_data_double.at(label).front();
456 } else {
457 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.");
458 }
459 } else if constexpr (std::is_same_v<T, vec2>) {
460 if (type == HELIOS_TYPE_VEC2) {
461 data = object_data_vec2.at(label).front();
462 } else {
463 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.");
464 }
465 } else if constexpr (std::is_same_v<T, vec3>) {
466 if (type == HELIOS_TYPE_VEC3) {
467 data = object_data_vec3.at(label).front();
468 } else {
469 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.");
470 }
471 } else if constexpr (std::is_same_v<T, vec4>) {
472 if (type == HELIOS_TYPE_VEC4) {
473 data = object_data_vec4.at(label).front();
474 } else {
475 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.");
476 }
477 } else if constexpr (std::is_same_v<T, int2>) {
478 if (type == HELIOS_TYPE_INT2) {
479 data = object_data_int2.at(label).front();
480 } else {
481 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.");
482 }
483 } else if constexpr (std::is_same_v<T, int3>) {
484 if (type == HELIOS_TYPE_INT3) {
485 data = object_data_int3.at(label).front();
486 } else {
487 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.");
488 }
489 } else if constexpr (std::is_same_v<T, int4>) {
490 if (type == HELIOS_TYPE_INT4) {
491 data = object_data_int4.at(label).front();
492 } else {
493 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.");
494 }
495 } 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 *>) {
496 if (type == HELIOS_TYPE_STRING) {
497 data = object_data_string.at(label).front();
498 } else {
499 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.");
500 }
501 }
502 }
503
505
510 template<typename T>
511 void getObjectData(const char *label, std::vector<T> &data) const {
512#ifdef HELIOS_DEBUG
513 if (!doesObjectDataExist(label)) {
514 helios_runtime_error("ERROR (CompoundObject::getObjectData): Object data " + std::string(label) + " does not exist for object " + std::to_string(OID));
515 }
516#endif
517
518 HeliosDataType type = object_data_types.at(label);
519
520 if constexpr (std::is_same_v<T, int>) {
521 if (type == HELIOS_TYPE_INT) {
522 data = object_data_int.at(label);
523 } else {
524 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.");
525 }
526 } else if constexpr (std::is_same_v<T, uint>) {
527 if (type == HELIOS_TYPE_UINT) {
528 data = object_data_uint.at(label);
529 } else {
530 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.");
531 }
532 } else if constexpr (std::is_same_v<T, float>) {
533 if (type == HELIOS_TYPE_FLOAT) {
534 data = object_data_float.at(label);
535 } else {
536 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.");
537 }
538 } else if constexpr (std::is_same_v<T, double>) {
539 if (type == HELIOS_TYPE_DOUBLE) {
540 data = object_data_double.at(label);
541 } else {
542 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.");
543 }
544 } else if constexpr (std::is_same_v<T, vec2>) {
545 if (type == HELIOS_TYPE_VEC2) {
546 data = object_data_vec2.at(label);
547 } else {
548 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.");
549 }
550 } else if constexpr (std::is_same_v<T, vec3>) {
551 if (type == HELIOS_TYPE_VEC3) {
552 data = object_data_vec3.at(label);
553 } else {
554 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.");
555 }
556 } else if constexpr (std::is_same_v<T, vec4>) {
557 if (type == HELIOS_TYPE_VEC4) {
558 data = object_data_vec4.at(label);
559 } else {
560 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.");
561 }
562 } else if constexpr (std::is_same_v<T, int2>) {
563 if (type == HELIOS_TYPE_INT2) {
564 data = object_data_int2.at(label);
565 } else {
566 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.");
567 }
568 } else if constexpr (std::is_same_v<T, int3>) {
569 if (type == HELIOS_TYPE_INT3) {
570 data = object_data_int3.at(label);
571 } else {
572 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.");
573 }
574 } else if constexpr (std::is_same_v<T, int4>) {
575 if (type == HELIOS_TYPE_INT4) {
576 data = object_data_int4.at(label);
577 } else {
578 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.");
579 }
580 } 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 *>) {
581 if (type == HELIOS_TYPE_STRING) {
582 data = object_data_string.at(label);
583 } else {
584 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.");
585 }
586 }
587 }
588
590
595 HeliosDataType getObjectDataType(const char *label) const;
596
598
602 uint getObjectDataSize(const char *label) const;
603
605
609 bool doesObjectDataExist(const char *label) const;
610
612
615 void clearObjectData(const char *label);
616
618 [[nodiscard]] std::vector<std::string> listObjectData() const;
619
620 protected:
622 uint OID;
623
626
628 std::vector<uint> UUIDs;
629
631 helios::Context *context;
632
634 std::string texturefile;
635
637 float transform[16];
638
640 helios::vec3 object_origin;
641
643 bool primitivesarecomplete = true;
644
645 std::map<std::string, HeliosDataType> object_data_types;
646 std::map<std::string, std::vector<int>> object_data_int;
647 std::map<std::string, std::vector<uint>> object_data_uint;
648 std::map<std::string, std::vector<float>> object_data_float;
649 std::map<std::string, std::vector<double>> object_data_double;
650 std::map<std::string, std::vector<vec2>> object_data_vec2;
651 std::map<std::string, std::vector<vec3>> object_data_vec3;
652 std::map<std::string, std::vector<vec4>> object_data_vec4;
653 std::map<std::string, std::vector<int2>> object_data_int2;
654 std::map<std::string, std::vector<int3>> object_data_int3;
655 std::map<std::string, std::vector<int4>> object_data_int4;
656 std::map<std::string, std::vector<std::string>> object_data_string;
657 std::map<std::string, std::vector<bool>> object_data_bool;
658
659 bool ishidden = false;
660
661 friend class Context;
662 };
663
665 class Tile final : public CompoundObject {
666 public:
668 ~Tile() override = default;
669
671 [[nodiscard]] helios::vec2 getSize() const;
672
674 [[nodiscard]] helios::vec3 getCenter() const;
675
677 [[nodiscard]] helios::int2 getSubdivisionCount() const;
678
680
684 void setSubdivisionCount(const helios::int2 &subdiv);
685
687 [[nodiscard]] std::vector<helios::vec3> getVertices() const;
688
690 [[nodiscard]] helios::vec3 getNormal() const;
691
693 [[nodiscard]] std::vector<helios::vec2> getTextureUV() const;
694
695 protected:
697
700 Tile(uint a_OID, const std::vector<uint> &a_UUIDs, const int2 &a_subdiv, const char *a_texturefile, helios::Context *a_context);
701
702 helios::int2 subdiv;
703
704 friend class CompoundObject;
705 friend class Context;
706 };
707
709 class Sphere final : public CompoundObject {
710 public:
712 ~Sphere() override = default;
713
715 [[nodiscard]] helios::vec3 getRadius() const;
716
718 [[nodiscard]] helios::vec3 getCenter() const;
719
721 [[nodiscard]] uint getSubdivisionCount() const;
722
724
727 void setSubdivisionCount(uint subdiv);
728
730 [[nodiscard]] float getVolume() const;
731
732 protected:
734
737 Sphere(uint a_OID, const std::vector<uint> &a_UUIDs, uint a_subdiv, const char *a_texturefile, helios::Context *a_context);
738
739 uint subdiv;
740
741 friend class CompoundObject;
742 friend class Context;
743 };
744
746 class Tube final : public CompoundObject {
747 public:
749 ~Tube() override = default;
750
752 [[nodiscard]] std::vector<helios::vec3> getNodes() const;
753
755 [[nodiscard]] uint getNodeCount() const;
756
758 [[nodiscard]] std::vector<float> getNodeRadii() const;
759
761 [[nodiscard]] std::vector<helios::RGBcolor> getNodeColors() const;
762
764 [[nodiscard]] std::vector<std::vector<helios::vec3>> getTriangleVertices() const;
765
767 [[nodiscard]] uint getSubdivisionCount() const;
768
770 [[nodiscard]] float getLength() const;
771
773 [[nodiscard]] float getVolume() const;
774
776
779 [[nodiscard]] float getSegmentVolume(uint segment_index) const;
780
782
787 void appendTubeSegment(const helios::vec3 &node_position, float node_radius, const helios::RGBcolor &node_color);
788
790
796 void appendTubeSegment(const helios::vec3 &node_position, float node_radius, const char *texturefile, const helios::vec2 &textureuv_ufrac);
797
799
802 void scaleTubeGirth(float S);
803
805
808 void setTubeRadii(const std::vector<float> &node_radii);
809
811
814 void scaleTubeLength(float S);
815
817
820 void setTubeNodes(const std::vector<helios::vec3> &node_xyz);
821
823
826 void pruneTubeNodes(uint node_index);
827
828 protected:
830
833 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,
834 uint a_subdiv, const char *a_texturefile, helios::Context *a_context);
835
836 std::vector<helios::vec3> nodes;
837
838 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
839
840 std::vector<float> radius;
841
842 std::vector<helios::RGBcolor> colors;
843
844 uint subdiv;
845
846 void updateTriangleVertices() const;
847
848 friend class CompoundObject;
849 friend class Context;
850 };
851
853 class Box final : public CompoundObject {
854 public:
856 ~Box() override = default;
857
859 [[nodiscard]] helios::vec3 getSize() const;
860
862 [[nodiscard]] helios::vec3 getCenter() const;
863
865 [[nodiscard]] helios::int3 getSubdivisionCount() const;
866
868
871 void setSubdivisionCount(const helios::int3 &subdiv);
872
874 [[nodiscard]] float getVolume() const;
875
876 protected:
878
881 Box(uint a_OID, const std::vector<uint> &a_UUIDs, const int3 &a_subdiv, const char *a_texturefile, helios::Context *a_context);
882
883 helios::int3 subdiv;
884
885 friend class CompoundObject;
886 friend class Context;
887 };
888
890 class Disk final : public CompoundObject {
891 public:
893 ~Disk() override = default;
894
896 [[nodiscard]] helios::vec2 getSize() const;
897
899 [[nodiscard]] helios::vec3 getCenter() const;
900
902 [[nodiscard]] helios::int2 getSubdivisionCount() const;
903
905
908 void setSubdivisionCount(const helios::int2 &subdiv);
909
910 protected:
912
915 Disk(uint a_OID, const std::vector<uint> &a_UUIDs, int2 a_subdiv, const char *a_texturefile, helios::Context *a_context);
916
917 int2 subdiv;
918
919 friend class CompoundObject;
920 friend class Context;
921 };
922
924 class Polymesh final : public CompoundObject {
925 public:
927 ~Polymesh() override = default;
928
930 [[nodiscard]] float getVolume() const;
931
932 protected:
934
937 Polymesh(uint a_OID, const std::vector<uint> &a_UUIDs, const char *a_texturefile, helios::Context *a_context);
938
939 friend class CompoundObject;
940 friend class Context;
941 };
942
944 class Cone final : public CompoundObject {
945 public:
947 ~Cone() override = default;
948
950
953 [[nodiscard]] std::vector<helios::vec3> getNodeCoordinates() const;
954
956
960 [[nodiscard]] helios::vec3 getNodeCoordinate(int node_index) const;
961
963
966 [[nodiscard]] std::vector<float> getNodeRadii() const;
967
969
973 [[nodiscard]] float getNodeRadius(int node_index) const;
974
976 [[nodiscard]] uint getSubdivisionCount() const;
977
979
982 void setSubdivisionCount(uint subdiv);
983
985 [[nodiscard]] helios::vec3 getAxisUnitVector() const;
986
988 [[nodiscard]] float getLength() const;
989
991
994 void scaleLength(float S);
995
997
1000 void scaleGirth(float S);
1001
1003 [[nodiscard]] float getVolume() const;
1004
1005 protected:
1007
1010 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);
1011
1012 std::vector<helios::vec3> nodes;
1013 std::vector<float> radii;
1014
1015 uint subdiv;
1016
1017 friend class CompoundObject;
1018 friend class Context;
1019 };
1020
1021
1023
1027 class Primitive {
1028 public:
1030
1033 virtual ~Primitive() = 0;
1034
1036
1039 [[nodiscard]] uint getUUID() const;
1040
1042
1045 [[nodiscard]] PrimitiveType getType() const;
1046
1048
1051 void setParentObjectID(uint objID);
1052
1054 [[nodiscard]] uint getParentObjectID() const;
1055
1057 [[nodiscard]] virtual float getArea() const = 0;
1058
1060 [[nodiscard]] virtual helios::vec3 getNormal() const = 0;
1061
1063
1066 void getTransformationMatrix(float (&T)[16]) const;
1067
1069
1072 void setTransformationMatrix(float (&T)[16]);
1073
1075 [[nodiscard]] virtual std::vector<helios::vec3> getVertices() const = 0;
1076
1078 [[nodiscard]] virtual helios::vec3 getCenter() const = 0;
1079
1081 [[nodiscard]] helios::RGBcolor getColor() const;
1082
1084 [[nodiscard]] helios::RGBcolor getColorRGB() const;
1085
1087 [[nodiscard]] helios::RGBAcolor getColorRGBA() const;
1088
1090
1093 void setColor(const helios::RGBcolor &color);
1094
1096
1099 void setColor(const helios::RGBAcolor &color);
1100
1102 [[nodiscard]] bool hasTexture() const;
1103
1105 [[nodiscard]] std::string getTextureFile() const;
1106
1108
1111 void setTextureFile(const char *texture);
1112
1114
1117 [[nodiscard]] std::vector<vec2> getTextureUV();
1118
1119
1121
1124 void setTextureUV(const std::vector<vec2> &uv);
1125
1127 void overrideTextureColor();
1128
1130 void useTextureColor();
1131
1133 [[nodiscard]] bool isTextureColorOverridden() const;
1134
1136
1139 [[nodiscard]] float getSolidFraction() const;
1140
1142
1145 void setSolidFraction(float solidFraction);
1146
1148
1151 void applyTransform(float (&T)[16]);
1152
1154
1157 void translate(const helios::vec3 &shift);
1158
1160
1164 virtual void rotate(float rotation_radians, const char *rotation_axis_xyz_string) = 0;
1165
1167
1171 virtual void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) = 0;
1172
1174
1179 virtual void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) = 0;
1180
1182
1185 void scale(const helios::vec3 &S);
1186
1188
1192 void scale(const helios::vec3 &S, const helios::vec3 &point);
1193
1194 //-------- Primitive Data Methods ---------- //
1195
1197
1202 template<typename T>
1203 void setPrimitiveData(const char *label, const T &data) {
1204 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> ||
1205 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 *>,
1206 "Primitive::setPrimitiveData() was called with an unsupported type.");
1207
1208 if constexpr (std::is_same_v<T, int>) {
1209 primitive_data_int[label] = {data};
1210 primitive_data_types[label] = HELIOS_TYPE_INT;
1211 } else if constexpr (std::is_same_v<T, uint>) {
1212 primitive_data_uint[label] = {data};
1213 primitive_data_types[label] = HELIOS_TYPE_UINT;
1214 } else if constexpr (std::is_same_v<T, float>) {
1215 primitive_data_float[label] = {data};
1216 primitive_data_types[label] = HELIOS_TYPE_FLOAT;
1217 } else if constexpr (std::is_same_v<T, double>) {
1218 primitive_data_double[label] = {data};
1219 primitive_data_types[label] = HELIOS_TYPE_DOUBLE;
1220 } else if constexpr (std::is_same_v<T, vec2>) {
1221 primitive_data_vec2[label] = {data};
1222 primitive_data_types[label] = HELIOS_TYPE_VEC2;
1223 } else if constexpr (std::is_same_v<T, vec3>) {
1224 primitive_data_vec3[label] = {data};
1225 primitive_data_types[label] = HELIOS_TYPE_VEC3;
1226 } else if constexpr (std::is_same_v<T, vec4>) {
1227 primitive_data_vec4[label] = {data};
1228 primitive_data_types[label] = HELIOS_TYPE_VEC4;
1229 } else if constexpr (std::is_same_v<T, int2>) {
1230 primitive_data_int2[label] = {data};
1231 primitive_data_types[label] = HELIOS_TYPE_INT2;
1232 } else if constexpr (std::is_same_v<T, int3>) {
1233 primitive_data_int3[label] = {data};
1234 primitive_data_types[label] = HELIOS_TYPE_INT3;
1235 } else if constexpr (std::is_same_v<T, int4>) {
1236 primitive_data_int4[label] = {data};
1237 primitive_data_types[label] = HELIOS_TYPE_INT4;
1238 } 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 *>) {
1239 primitive_data_string[label] = {data};
1240 primitive_data_types[label] = HELIOS_TYPE_STRING;
1241 }
1242 dirty_flag = true;
1243 }
1244
1246
1251 template<typename T>
1252 void setPrimitiveData(const char *label, const std::vector<T> &data) {
1253 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> ||
1254 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 *>,
1255 "Primitive::setPrimitiveData() was called with an unsupported type.");
1256
1257 if constexpr (std::is_same_v<T, int>) {
1258 primitive_data_int[label] = data;
1259 primitive_data_types[label] = HELIOS_TYPE_INT;
1260 } else if constexpr (std::is_same_v<T, uint>) {
1261 primitive_data_uint[label] = data;
1262 primitive_data_types[label] = HELIOS_TYPE_UINT;
1263 } else if constexpr (std::is_same_v<T, float>) {
1264 primitive_data_float[label] = data;
1265 primitive_data_types[label] = HELIOS_TYPE_FLOAT;
1266 } else if constexpr (std::is_same_v<T, double>) {
1267 primitive_data_double[label] = data;
1268 primitive_data_types[label] = HELIOS_TYPE_DOUBLE;
1269 } else if constexpr (std::is_same_v<T, vec2>) {
1270 primitive_data_vec2[label] = data;
1271 primitive_data_types[label] = HELIOS_TYPE_VEC2;
1272 } else if constexpr (std::is_same_v<T, vec3>) {
1273 primitive_data_vec3[label] = data;
1274 primitive_data_types[label] = HELIOS_TYPE_VEC3;
1275 } else if constexpr (std::is_same_v<T, vec4>) {
1276 primitive_data_vec4[label] = data;
1277 primitive_data_types[label] = HELIOS_TYPE_VEC4;
1278 } else if constexpr (std::is_same_v<T, int2>) {
1279 primitive_data_int2[label] = data;
1280 primitive_data_types[label] = HELIOS_TYPE_INT2;
1281 } else if constexpr (std::is_same_v<T, int3>) {
1282 primitive_data_int3[label] = data;
1283 primitive_data_types[label] = HELIOS_TYPE_INT3;
1284 } else if constexpr (std::is_same_v<T, int4>) {
1285 primitive_data_int4[label] = data;
1286 primitive_data_types[label] = HELIOS_TYPE_INT4;
1287 } 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 *>) {
1288 primitive_data_string[label] = data;
1289 primitive_data_types[label] = HELIOS_TYPE_STRING;
1290 }
1291 dirty_flag = true;
1292 }
1293
1295
1300 template<typename T>
1301 void getPrimitiveData(const char *label, T &data) const {
1302#ifdef HELIOS_DEBUG
1303 if (!doesPrimitiveDataExist(label)) {
1304 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
1305 }
1306#endif
1307 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> ||
1308 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 *>,
1309 "Primitive::getPrimitiveData() was called with an unsupported type.");
1310
1311 HeliosDataType type = primitive_data_types.at(label);
1312
1313 if constexpr (std::is_same_v<T, int>) {
1314 if (type == HELIOS_TYPE_INT) {
1315 data = primitive_data_int.at(label).front();
1316 } else {
1317 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.");
1318 }
1319 } else if constexpr (std::is_same_v<T, uint>) {
1320 if (type == HELIOS_TYPE_UINT) {
1321 data = primitive_data_uint.at(label).front();
1322 } else {
1323 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.");
1324 }
1325 } else if constexpr (std::is_same_v<T, float>) {
1326 if (type == HELIOS_TYPE_FLOAT) {
1327 data = primitive_data_float.at(label).front();
1328 } else {
1329 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.");
1330 }
1331 } else if constexpr (std::is_same_v<T, double>) {
1332 if (type == HELIOS_TYPE_DOUBLE) {
1333 data = primitive_data_double.at(label).front();
1334 } else {
1335 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.");
1336 }
1337 } else if constexpr (std::is_same_v<T, vec2>) {
1338 if (type == HELIOS_TYPE_VEC2) {
1339 data = primitive_data_vec2.at(label).front();
1340 } else {
1341 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.");
1342 }
1343 } else if constexpr (std::is_same_v<T, vec3>) {
1344 if (type == HELIOS_TYPE_VEC3) {
1345 data = primitive_data_vec3.at(label).front();
1346 } else {
1347 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.");
1348 }
1349 } else if constexpr (std::is_same_v<T, vec4>) {
1350 if (type == HELIOS_TYPE_VEC4) {
1351 data = primitive_data_vec4.at(label).front();
1352 } else {
1353 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.");
1354 }
1355 } else if constexpr (std::is_same_v<T, int2>) {
1356 if (type == HELIOS_TYPE_INT2) {
1357 data = primitive_data_int2.at(label).front();
1358 } else {
1359 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.");
1360 }
1361 } else if constexpr (std::is_same_v<T, int3>) {
1362 if (type == HELIOS_TYPE_INT3) {
1363 data = primitive_data_int3.at(label).front();
1364 } else {
1365 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.");
1366 }
1367 } else if constexpr (std::is_same_v<T, int4>) {
1368 if (type == HELIOS_TYPE_INT4) {
1369 data = primitive_data_int4.at(label).front();
1370 } else {
1371 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.");
1372 }
1373 } 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 *>) {
1374 if (type == HELIOS_TYPE_STRING) {
1375 data = primitive_data_string.at(label).front();
1376 } else {
1377 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.");
1378 }
1379 }
1380 }
1381
1383
1388 template<typename T>
1389 void getPrimitiveData(const char *label, std::vector<T> &data) const {
1390#ifdef HELIOS_DEBUG
1391 if (!doesPrimitiveDataExist(label)) {
1392 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
1393 }
1394#endif
1395 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> ||
1396 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 *>,
1397 "Primitive::getPrimitiveData() was called with an unsupported type.");
1398
1399 HeliosDataType type = primitive_data_types.at(label);
1400
1401 if constexpr (std::is_same_v<T, int>) {
1402 if (type == HELIOS_TYPE_INT) {
1403 data = primitive_data_int.at(label);
1404 } else {
1405 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.");
1406 }
1407 } else if constexpr (std::is_same_v<T, uint>) {
1408 if (type == HELIOS_TYPE_UINT) {
1409 data = primitive_data_uint.at(label);
1410 } else {
1411 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.");
1412 }
1413 } else if constexpr (std::is_same_v<T, float>) {
1414 if (type == HELIOS_TYPE_FLOAT) {
1415 data = primitive_data_float.at(label);
1416 } else {
1417 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.");
1418 }
1419 } else if constexpr (std::is_same_v<T, double>) {
1420 if (type == HELIOS_TYPE_DOUBLE) {
1421 data = primitive_data_double.at(label);
1422 } else {
1423 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.");
1424 }
1425 } else if constexpr (std::is_same_v<T, vec2>) {
1426 if (type == HELIOS_TYPE_VEC2) {
1427 data = primitive_data_vec2.at(label);
1428 } else {
1429 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.");
1430 }
1431 } else if constexpr (std::is_same_v<T, vec3>) {
1432 if (type == HELIOS_TYPE_VEC3) {
1433 data = primitive_data_vec3.at(label);
1434 } else {
1435 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.");
1436 }
1437 } else if constexpr (std::is_same_v<T, vec4>) {
1438 if (type == HELIOS_TYPE_VEC4) {
1439 data = primitive_data_vec4.at(label);
1440 } else {
1441 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.");
1442 }
1443 } else if constexpr (std::is_same_v<T, int2>) {
1444 if (type == HELIOS_TYPE_INT2) {
1445 data = primitive_data_int2.at(label);
1446 } else {
1447 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.");
1448 }
1449 } else if constexpr (std::is_same_v<T, int3>) {
1450 if (type == HELIOS_TYPE_INT3) {
1451 data = primitive_data_int3.at(label);
1452 } else {
1453 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.");
1454 }
1455 } else if constexpr (std::is_same_v<T, int4>) {
1456 if (type == HELIOS_TYPE_INT4) {
1457 data = primitive_data_int4.at(label);
1458 } else {
1459 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.");
1460 }
1461 } 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 *>) {
1462 if (type == HELIOS_TYPE_STRING) {
1463 data = primitive_data_string.at(label);
1464 } else {
1465 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.");
1466 }
1467 }
1468 }
1469
1471
1476 HeliosDataType getPrimitiveDataType(const char *label) const;
1477
1479
1483 uint getPrimitiveDataSize(const char *label) const;
1484
1486
1490 bool doesPrimitiveDataExist(const char *label) const;
1491
1493
1496 void clearPrimitiveData(const char *label);
1497
1499 [[nodiscard]] std::vector<std::string> listPrimitiveData() const;
1500
1501 protected:
1503 uint UUID;
1504
1506 PrimitiveType prim_type;
1507
1509 uint parent_object_ID;
1510
1512 helios::RGBAcolor color;
1513
1515 std::string texturefile;
1517 float transform[16];
1518
1520 std::vector<vec2> uv;
1521
1523 float solid_fraction;
1524
1526 bool dirty_flag;
1527
1528 std::map<std::string, HeliosDataType> primitive_data_types;
1529 std::map<std::string, std::vector<int>> primitive_data_int;
1530 std::map<std::string, std::vector<uint>> primitive_data_uint;
1531 std::map<std::string, std::vector<float>> primitive_data_float;
1532 std::map<std::string, std::vector<double>> primitive_data_double;
1533 std::map<std::string, std::vector<vec2>> primitive_data_vec2;
1534 std::map<std::string, std::vector<vec3>> primitive_data_vec3;
1535 std::map<std::string, std::vector<vec4>> primitive_data_vec4;
1536 std::map<std::string, std::vector<int2>> primitive_data_int2;
1537 std::map<std::string, std::vector<int3>> primitive_data_int3;
1538 std::map<std::string, std::vector<int4>> primitive_data_int4;
1539 std::map<std::string, std::vector<std::string>> primitive_data_string;
1540 std::map<std::string, std::vector<bool>> primitive_data_bool;
1541
1542 bool texturecoloroverridden = false;
1543
1544 bool ishidden = false;
1545
1546 friend class Context;
1547 };
1548
1549
1551
1556 class Patch : public Primitive {
1557 public:
1559 ~Patch() override = default;
1560
1562
1565 [[nodiscard]] float getArea() const override;
1566
1568
1571 [[nodiscard]] helios::vec3 getNormal() const override;
1572
1574
1577 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
1578
1580
1583 [[nodiscard]] helios::vec2 getSize() const;
1584
1586
1589 [[nodiscard]] helios::vec3 getCenter() const override;
1590
1592
1596 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
1597
1599
1603 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
1604
1606
1611 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
1612
1613 protected:
1615
1621 Patch(const helios::RGBAcolor &color, uint parent_objID, uint UUID);
1622
1624
1631 Patch(const char *texturefile, float solid_fraction, uint parent_objID, uint UUID);
1632
1634
1642 Patch(const char *texturefile, const std::vector<helios::vec2> &uv, std::map<std::string, Texture> &textures, uint parent_objID, uint UUID);
1643
1644
1645 friend class Primitive;
1646 friend class Context;
1647 };
1648
1650
1655 class Triangle : public Primitive {
1656 public:
1658 ~Triangle() override = default;
1659
1661
1664 [[nodiscard]] float getArea() const override;
1665
1667
1670 [[nodiscard]] helios::vec3 getNormal() const override;
1671
1673
1676 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
1677
1679
1683 [[nodiscard]] helios::vec3 getVertex(int vertex_index) const;
1684
1686
1689 [[nodiscard]] helios::vec3 getCenter() const override;
1690
1692
1696 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
1697
1699
1703 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
1704
1706
1711 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
1712
1714
1719 void setVertices(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
1720
1721 private:
1723
1732 Triangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBAcolor &color, uint parent_objID, uint UUID);
1733
1735
1746 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);
1747
1749
1760 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);
1761
1762 void makeTransformationMatrix(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
1763
1764 bool edgeFunction(const helios::vec2 &a, const helios::vec2 &b, const helios::vec2 &c);
1765
1766 friend class Primitive;
1767 friend class Context;
1768 };
1769
1771
1774 class Voxel : public Primitive {
1775 public:
1777 ~Voxel() override = default;
1778
1780
1783 [[nodiscard]] float getArea() const override;
1784
1786 [[nodiscard]] helios::vec3 getNormal() const override;
1787
1789
1792 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
1793
1795
1798 float getVolume();
1799
1801
1804 [[nodiscard]] helios::vec3 getCenter() const override;
1805
1807
1810 [[nodiscard]] helios::vec3 getSize() const;
1811
1813
1817 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
1818
1820
1824 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
1825
1826
1828
1833 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
1834
1835 protected:
1837
1843 Voxel(const helios::RGBAcolor &color, uint parent_objID, uint UUID);
1844
1845 friend class Primitive;
1846 friend class Context;
1847 };
1848
1851 public:
1853
1858 static int parse_data_float(const pugi::xml_node &node_data, std::vector<float> &data);
1859
1861
1866 static int parse_data_double(const pugi::xml_node &node_data, std::vector<double> &data);
1867
1869
1874 static int parse_data_int(const pugi::xml_node &node_data, std::vector<int> &data);
1875
1877
1882 static int parse_data_uint(const pugi::xml_node &node_data, std::vector<uint> &data);
1883
1885
1890 static int parse_data_string(const pugi::xml_node &node_data, std::vector<std::string> &data);
1891
1893
1898 static int parse_data_vec2(const pugi::xml_node &node_data, std::vector<vec2> &data);
1899
1901
1906 static int parse_data_vec3(const pugi::xml_node &node_data, std::vector<vec3> &data);
1907
1909
1914 static int parse_data_vec4(const pugi::xml_node &node_data, std::vector<vec4> &data);
1915
1917
1922 static int parse_data_int2(const pugi::xml_node &node_data, std::vector<int2> &data);
1923
1925
1930 static int parse_data_int3(const pugi::xml_node &node_data, std::vector<int3> &data);
1931
1933
1938 static int parse_data_int4(const pugi::xml_node &node_data, std::vector<int4> &data);
1939
1941
1946 static int parse_objID(const pugi::xml_node &node_data, uint &objID);
1947
1949
1954 static int parse_transform(const pugi::xml_node &node_data, float (&transform)[16]);
1955
1957
1962 static int parse_texture(const pugi::xml_node &node_data, std::string &texture);
1963
1965
1970 static int parse_textureUV(const pugi::xml_node &node_data, std::vector<vec2> &uvs);
1971
1973
1978 static int parse_solid_fraction(const pugi::xml_node &node_data, float &solid_fraction);
1979
1981
1986 static int parse_vertices(const pugi::xml_node &node_data, std::vector<float> &vertices);
1987
1989
1994 static int parse_subdivisions(const pugi::xml_node &node_data, uint &subdivisions);
1995
1997
2002 static int parse_subdivisions(const pugi::xml_node &node_data, int2 &subdivisions);
2003
2005
2010 static int parse_subdivisions(const pugi::xml_node &node_data, int3 &subdivisions);
2011
2013
2018 static int parse_nodes(const pugi::xml_node &node_data, std::vector<vec3> &nodes);
2019
2021
2026 static int parse_radius(const pugi::xml_node &node_data, std::vector<float> &radius);
2027 };
2028
2030
2033 class Context {
2034 private:
2035 //---------- PRIMITIVE/OBJECT HELIOS::VECTORS ----------------//
2036
2038
2042 [[nodiscard]] Primitive *getPrimitivePointer_private(uint UUID) const;
2043
2045
2049 [[nodiscard]] Patch *getPatchPointer_private(uint UUID) const;
2050
2051
2053
2057 [[nodiscard]] Triangle *getTrianglePointer_private(uint UUID) const;
2058
2060
2064 [[nodiscard]] Voxel *getVoxelPointer_private(uint UUID) const;
2065
2067
2071 [[nodiscard]] CompoundObject *getObjectPointer_private(uint ObjID) const;
2072
2074
2078 [[nodiscard]] Tile *getTileObjectPointer_private(uint ObjID) const;
2079
2081
2085 [[nodiscard]] Sphere *getSphereObjectPointer_private(uint ObjID) const;
2086
2088
2092 [[nodiscard]] Tube *getTubeObjectPointer_private(uint ObjID) const;
2093
2095
2099 [[nodiscard]] Box *getBoxObjectPointer_private(uint ObjID) const;
2100
2102
2106 [[nodiscard]] Disk *getDiskObjectPointer_private(uint ObjID) const;
2107
2109
2113 [[nodiscard]] Polymesh *getPolymeshObjectPointer_private(uint ObjID) const;
2114
2116
2120 [[nodiscard]] Cone *getConeObjectPointer_private(uint ObjID) const;
2121
2123 void invalidateAllUUIDsCache() const {
2124 all_uuids_cache_valid = false;
2125 }
2126
2128
2131 std::unordered_map<uint, Primitive *> primitives;
2132
2134 mutable std::vector<uint> cached_all_uuids;
2136 mutable bool all_uuids_cache_valid = false;
2137
2139 std::vector<uint> dirty_deleted_primitives;
2140
2142 std::unordered_map<uint, CompoundObject *> objects;
2143
2145 std::map<std::string, std::vector<float>> timeseries_data;
2146
2148
2149 std::map<std::string, std::vector<double>> timeseries_datevalue;
2150
2151 //------------ TEXTURES ----------------//
2152
2153 std::map<std::string, Texture> textures;
2154
2155 void addTexture(const char *texture_file);
2156
2157
2158 bool doesTextureFileExist(const char *texture_file) const;
2159
2160 bool validateTextureFileExtenstion(const char *texture_file) const;
2161
2162 //----------- GLOBAL DATA -------------//
2163
2164 std::map<std::string, GlobalData> globaldata;
2165
2166 std::unordered_map<std::string, size_t> primitive_data_label_counts;
2167 std::unordered_map<std::string, size_t> object_data_label_counts;
2168
2169 //----------- DATA TYPE CONSISTENCY REGISTRIES -------------//
2170
2172 std::unordered_map<std::string, HeliosDataType> primitive_data_type_registry;
2173
2175 std::unordered_map<std::string, HeliosDataType> object_data_type_registry;
2176
2177 //----------- VALUE-LEVEL CACHING REGISTRIES -------------//
2178
2180 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> primitive_string_value_registry;
2181 std::unordered_map<std::string, std::unordered_map<int, size_t>> primitive_int_value_registry;
2182 std::unordered_map<std::string, std::unordered_map<uint, size_t>> primitive_uint_value_registry;
2183
2185 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> object_string_value_registry;
2186 std::unordered_map<std::string, std::unordered_map<int, size_t>> object_int_value_registry;
2187 std::unordered_map<std::string, std::unordered_map<uint, size_t>> object_uint_value_registry;
2188
2190 std::unordered_set<std::string> cached_primitive_data_labels;
2191 std::unordered_set<std::string> cached_object_data_labels;
2192
2194
2197 void incrementPrimitiveDataLabelCounter(const std::string &primitive_data_label);
2198
2200
2203 void decrementPrimitiveDataLabelCounter(const std::string &primitive_data_label);
2204
2205
2207
2210 void incrementObjectDataLabelCounter(const std::string &object_data_label);
2211
2213
2216 void decrementObjectDataLabelCounter(const std::string &object_data_label);
2217
2219 std::string dataTypeToString(HeliosDataType type) const;
2220
2222 bool isTypeCastingSupported(HeliosDataType from_type, HeliosDataType to_type) const;
2223
2224 //---------- CONTEXT PRIVATE MEMBER VARIABLES ---------//
2225
2227
2230 helios::Date sim_date;
2231
2233
2236 helios::Time sim_time;
2237
2239 helios::Location sim_location;
2240
2242 std::minstd_rand0 generator;
2243
2245 std::uniform_real_distribution<float> unif_distribution;
2246
2248 std::normal_distribution<float> norm_distribution;
2249
2250 //---------- CONTEXT I/O ---------//
2251
2252 std::vector<std::string> XMLfiles;
2253
2254 struct OBJmaterial {
2255
2256 RGBcolor color;
2257 std::string texture;
2258 uint materialID;
2259 bool textureHasTransparency = false;
2260 bool textureColorIsOverridden = false;
2261
2262 OBJmaterial(const RGBcolor &a_color, std::string a_texture, uint a_materialID) : color{a_color}, texture{std::move(a_texture)}, materialID{a_materialID} {};
2263 };
2264
2265 std::map<std::string, OBJmaterial> loadMTL(const std::string &filebase, const std::string &material_file);
2266
2267 void loadPData(pugi::xml_node p, uint UUID);
2268
2269 void loadOData(pugi::xml_node p, uint ID);
2270
2271 void loadOsubPData(pugi::xml_node p, uint ID);
2272
2273 void writeDataToXMLstream(const char *data_group, const std::vector<std::string> &data_labels, void *ptr, std::ofstream &outfile) const;
2274
2275
2276 //---------- CONTEXT INITIALIZATION FLAGS ---------//
2277
2278 uint currentUUID;
2279
2280 uint currentObjectID;
2281
2282 //---------- MEMORY HANDLING -----------------//
2283
2285
2289 static void out_of_memory_handler();
2290
2292
2295 static void install_out_of_memory_handler();
2296
2297 public:
2299 Context();
2300
2302 ~Context();
2303
2305 Context(const Context &) = delete;
2306
2308 void operator=(const Context &) = delete;
2309
2311
2316 static int selfTest(int argc, char **argv);
2317
2319
2322 void seedRandomGenerator(uint seed);
2323
2325
2328 std::minstd_rand0 *getRandomGenerator();
2329
2331
2335 void markGeometryClean();
2336
2338
2342 void markGeometryDirty();
2343
2345
2349 [[nodiscard]] bool isGeometryDirty() const;
2350
2352
2355 void markPrimitiveDirty(uint UUID) const;
2356
2358
2361 void markPrimitiveDirty(const std::vector<uint> &UUIDs) const;
2362
2364
2367 void markPrimitiveClean(uint UUID) const;
2368
2370
2373 void markPrimitiveClean(const std::vector<uint> &UUIDs) const;
2374
2376
2380 [[nodiscard]] bool isPrimitiveDirty(uint UUID) const;
2381
2383
2386 uint addPatch();
2387
2389
2396 uint addPatch(const helios::vec3 &center, const helios::vec2 &size);
2397
2399
2407 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
2408
2410
2417 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
2418
2420
2426 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
2427
2429
2437 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
2438
2440
2450 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);
2451
2453
2460 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2461
2463
2471 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBcolor &color);
2472
2474
2482 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBAcolor &color);
2483
2485
2497 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);
2498
2500
2507 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size);
2508
2510
2518 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation);
2519
2521
2528 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation, const helios::RGBcolor &color);
2529
2531
2538 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation, const helios::RGBAcolor &color);
2539
2541
2545 void translatePrimitive(uint UUID, const vec3 &shift);
2546
2548
2552 void translatePrimitive(const std::vector<uint> &UUIDs, const vec3 &shift);
2553
2555
2560 void rotatePrimitive(uint UUID, float rotation_rad, const char *axis);
2561
2563
2568 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const char *axis);
2569
2571
2576 void rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &axis);
2577
2579
2584 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const vec3 &axis);
2585
2587
2593 void rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &origin, const helios::vec3 &axis);
2594
2596
2602 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const helios::vec3 &origin, const vec3 &axis);
2603
2605
2610 void setPrimitiveNormal(uint UUID, const helios::vec3 &origin, const helios::vec3 &new_normal);
2611
2613
2618 void setPrimitiveNormal(const std::vector<uint> &UUIDs, const helios::vec3 &origin, const vec3 &new_normal);
2619
2621
2626 void setPrimitiveElevation(uint UUID, const helios::vec3 &origin, float new_elevation);
2627
2629
2634 void setPrimitiveAzimuth(uint UUID, const helios::vec3 &origin, float new_azimuth);
2635
2637
2641 void scalePrimitive(uint UUID, const helios::vec3 &S);
2642
2644
2648 void scalePrimitive(const std::vector<uint> &UUIDs, const helios::vec3 &S);
2649
2651
2656 void scalePrimitiveAboutPoint(uint UUID, const helios::vec3 &S, const helios::vec3 &point);
2657
2659
2664 void scalePrimitiveAboutPoint(const std::vector<uint> &UUIDs, const helios::vec3 &S, const helios::vec3 &point);
2665
2667
2670 void deletePrimitive(uint UUID);
2671
2673
2676 void deletePrimitive(const std::vector<uint> &UUIDs);
2677
2679
2683 uint copyPrimitive(uint UUID);
2684
2686
2690 std::vector<uint> copyPrimitive(const std::vector<uint> &UUIDs);
2691
2693
2697 void copyPrimitiveData(uint sourceUUID, uint destinationUUID);
2698
2700
2705 void renamePrimitiveData(uint UUID, const char *old_label, const char *new_label);
2706
2708
2713 void duplicatePrimitiveData(uint UUID, const char *old_label, const char *new_label);
2714
2716
2719 [[nodiscard]] bool doesPrimitiveExist(uint UUID) const;
2720
2722
2726 [[nodiscard]] bool doesPrimitiveExist(const std::vector<uint> &UUIDs) const;
2727
2729
2734 [[nodiscard]] helios::vec2 getPatchSize(uint UUID) const;
2735
2737
2742 [[nodiscard]] helios::vec3 getPatchCenter(uint UUID) const;
2743
2745
2751 [[nodiscard]] helios::vec3 getTriangleVertex(uint UUID, uint number) const;
2752
2754
2760 void setTriangleVertices(uint UUID, const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2761
2763
2768 [[nodiscard]] helios::vec3 getVoxelCenter(uint UUID) const;
2769
2771
2776 [[nodiscard]] helios::vec3 getVoxelSize(uint UUID) const;
2777
2779
2783 [[nodiscard]] size_t getPrimitiveCount(bool include_hidden_primitives = true) const;
2784
2786
2790 [[nodiscard]] size_t getTriangleCount(bool include_hidden_primitives = true) const;
2791
2793
2797 [[nodiscard]] size_t getPatchCount(bool include_hidden_primitives = true) const;
2798
2800 [[nodiscard]] std::vector<uint> getAllUUIDs() const;
2801
2803
2807 [[nodiscard]] std::vector<uint> getDirtyUUIDs(bool include_deleted_UUIDs = false) const;
2808
2810
2813 [[nodiscard]] std::vector<uint> getDeletedUUIDs() const;
2814
2816
2819 void hidePrimitive(uint UUID) const;
2820
2822
2825 void hidePrimitive(const std::vector<uint> &UUIDs) const;
2826
2828
2831 void showPrimitive(uint UUID) const;
2832
2834
2837 void showPrimitive(const std::vector<uint> &UUIDs) const;
2838
2840
2844 [[nodiscard]] bool isPrimitiveHidden(uint UUID) const;
2845
2847
2850 void cleanDeletedUUIDs(std::vector<uint> &UUIDs) const;
2851
2853
2856 void cleanDeletedUUIDs(std::vector<std::vector<uint>> &UUIDs) const;
2857
2859
2862 void cleanDeletedUUIDs(std::vector<std::vector<std::vector<uint>>> &UUIDs) const;
2863
2864 //-------- Primitive Data Methods ---------- //
2865
2867
2873 template<typename T>
2874 void setPrimitiveData(uint UUID, const char *label, const T &data) {
2875#ifdef HELIOS_DEBUG
2876 if (primitives.find(UUID) == primitives.end()) {
2877 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
2878 }
2879#endif
2880 // Check if this primitive already has cached data for registry maintenance
2881 std::string label_str = std::string(label);
2882 bool had_cached_value = false;
2883
2884 // Handle caching only for supported types, and avoid character arrays
2885 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
2886 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
2887 T old_cached_value{};
2888 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
2889 decrementPrimitiveValueRegistry(label_str, old_cached_value);
2890 had_cached_value = true;
2891 }
2892 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
2893 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
2894 std::string old_cached_value;
2895 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
2896 decrementPrimitiveValueRegistry(label_str, old_cached_value);
2897 had_cached_value = true;
2898 }
2899 }
2900
2901 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
2902 incrementPrimitiveDataLabelCounter(label);
2903 }
2904
2905 // Validate data type consistency and register/validate type
2906 HeliosDataType data_type;
2907 if constexpr (std::is_same_v<T, int>) {
2908 data_type = HELIOS_TYPE_INT;
2909 } else if constexpr (std::is_same_v<T, uint>) {
2910 data_type = HELIOS_TYPE_UINT;
2911 } else if constexpr (std::is_same_v<T, float>) {
2912 data_type = HELIOS_TYPE_FLOAT;
2913 } else if constexpr (std::is_same_v<T, double>) {
2914 data_type = HELIOS_TYPE_DOUBLE;
2915 } else if constexpr (std::is_same_v<T, vec2>) {
2916 data_type = HELIOS_TYPE_VEC2;
2917 } else if constexpr (std::is_same_v<T, vec3>) {
2918 data_type = HELIOS_TYPE_VEC3;
2919 } else if constexpr (std::is_same_v<T, vec4>) {
2920 data_type = HELIOS_TYPE_VEC4;
2921 } else if constexpr (std::is_same_v<T, int2>) {
2922 data_type = HELIOS_TYPE_INT2;
2923 } else if constexpr (std::is_same_v<T, int3>) {
2924 data_type = HELIOS_TYPE_INT3;
2925 } else if constexpr (std::is_same_v<T, int4>) {
2926 data_type = HELIOS_TYPE_INT4;
2927 } 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 *>) {
2928 data_type = HELIOS_TYPE_STRING;
2929 }
2930 HeliosDataType target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
2931
2932 // Store data with type casting if needed
2933 if (target_type != data_type && isTypeCastingSupported(data_type, target_type)) {
2934 storeDataWithTypeCasting(UUID, label, data, target_type);
2935 } else {
2936 primitives.at(UUID)->setPrimitiveData(label, data);
2937 }
2938
2939 // Update value registry if caching is enabled for this label (only for new data)
2940 if (isPrimitiveDataValueCachingEnabled(label_str) && !had_cached_value) {
2941 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
2942 incrementPrimitiveValueRegistry(label_str, data);
2943 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
2944 incrementPrimitiveValueRegistry(label_str, std::string(data));
2945 }
2946 } else if (isPrimitiveDataValueCachingEnabled(label_str) && had_cached_value) {
2947 // For updates, just add the new value (old value was already decremented)
2948 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
2949 incrementPrimitiveValueRegistry(label_str, data);
2950 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
2951 incrementPrimitiveValueRegistry(label_str, std::string(data));
2952 }
2953 }
2954 }
2955
2957
2963 template<typename T>
2964 void setPrimitiveData(uint UUID, const char *label, const std::vector<T> &data) {
2965#ifdef HELIOS_DEBUG
2966 if (primitives.find(UUID) == primitives.end()) {
2967 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
2968 }
2969#endif
2970 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
2971 incrementPrimitiveDataLabelCounter(label);
2972 }
2973
2974 // For vector data, register the base type (not vector type)
2975 HeliosDataType data_type;
2976 if constexpr (std::is_same_v<T, int>) {
2977 data_type = HELIOS_TYPE_INT;
2978 } else if constexpr (std::is_same_v<T, uint>) {
2979 data_type = HELIOS_TYPE_UINT;
2980 } else if constexpr (std::is_same_v<T, float>) {
2981 data_type = HELIOS_TYPE_FLOAT;
2982 } else if constexpr (std::is_same_v<T, double>) {
2983 data_type = HELIOS_TYPE_DOUBLE;
2984 } else if constexpr (std::is_same_v<T, vec2>) {
2985 data_type = HELIOS_TYPE_VEC2;
2986 } else if constexpr (std::is_same_v<T, vec3>) {
2987 data_type = HELIOS_TYPE_VEC3;
2988 } else if constexpr (std::is_same_v<T, vec4>) {
2989 data_type = HELIOS_TYPE_VEC4;
2990 } else if constexpr (std::is_same_v<T, int2>) {
2991 data_type = HELIOS_TYPE_INT2;
2992 } else if constexpr (std::is_same_v<T, int3>) {
2993 data_type = HELIOS_TYPE_INT3;
2994 } else if constexpr (std::is_same_v<T, int4>) {
2995 data_type = HELIOS_TYPE_INT4;
2996 } 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 *>) {
2997 data_type = HELIOS_TYPE_STRING;
2998 }
2999 registerOrValidatePrimitiveDataType<T>(label, data_type);
3000
3001 primitives.at(UUID)->setPrimitiveData(label, data);
3002 }
3003
3005
3012 template<typename T>
3013 void setPrimitiveData(const std::vector<uint> &UUIDs, const char *label, const std::vector<T> &data) {
3014#ifdef HELIOS_DEBUG
3015 if (UUIDs.size() != data.size()) {
3016 helios_runtime_error("ERROR (Context::setPrimitiveData): UUIDs and data vectors must be the same size.");
3017 }
3018#endif
3019
3020 // Validate data type consistency and register/validate type (only once for all elements)
3021 HeliosDataType target_type = HELIOS_TYPE_UNKNOWN;
3022 if (!UUIDs.empty()) {
3023 HeliosDataType data_type;
3024 if constexpr (std::is_same_v<T, int>) {
3025 data_type = HELIOS_TYPE_INT;
3026 } else if constexpr (std::is_same_v<T, uint>) {
3027 data_type = HELIOS_TYPE_UINT;
3028 } else if constexpr (std::is_same_v<T, float>) {
3029 data_type = HELIOS_TYPE_FLOAT;
3030 } else if constexpr (std::is_same_v<T, double>) {
3031 data_type = HELIOS_TYPE_DOUBLE;
3032 } else if constexpr (std::is_same_v<T, vec2>) {
3033 data_type = HELIOS_TYPE_VEC2;
3034 } else if constexpr (std::is_same_v<T, vec3>) {
3035 data_type = HELIOS_TYPE_VEC3;
3036 } else if constexpr (std::is_same_v<T, vec4>) {
3037 data_type = HELIOS_TYPE_VEC4;
3038 } else if constexpr (std::is_same_v<T, int2>) {
3039 data_type = HELIOS_TYPE_INT2;
3040 } else if constexpr (std::is_same_v<T, int3>) {
3041 data_type = HELIOS_TYPE_INT3;
3042 } else if constexpr (std::is_same_v<T, int4>) {
3043 data_type = HELIOS_TYPE_INT4;
3044 } 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 *>) {
3045 data_type = HELIOS_TYPE_STRING;
3046 }
3047 target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
3048 }
3049
3050 for (uint UUID: UUIDs) {
3051#ifdef HELIOS_DEBUG
3052 if (primitives.find(UUID) == primitives.end()) {
3053 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3054 }
3055#endif
3056 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3057 incrementPrimitiveDataLabelCounter(label);
3058 }
3059 }
3060
3061#ifdef USE_OPENMP
3062#pragma omp parallel for
3063#endif
3064 for (int i = 0; i < (int) UUIDs.size(); ++i) {
3065 primitives.at(UUIDs[i])->setPrimitiveData(label, data[i]);
3066 }
3067 }
3068
3070
3076 template<typename T>
3077 void setPrimitiveData(const std::vector<uint> &UUIDs, const char *label, const T &data) {
3078
3079 // Validate data type consistency and register/validate type
3080 if (!UUIDs.empty()) {
3081 HeliosDataType data_type;
3082 if constexpr (std::is_same_v<T, int>) {
3083 data_type = HELIOS_TYPE_INT;
3084 } else if constexpr (std::is_same_v<T, uint>) {
3085 data_type = HELIOS_TYPE_UINT;
3086 } else if constexpr (std::is_same_v<T, float>) {
3087 data_type = HELIOS_TYPE_FLOAT;
3088 } else if constexpr (std::is_same_v<T, double>) {
3089 data_type = HELIOS_TYPE_DOUBLE;
3090 } else if constexpr (std::is_same_v<T, vec2>) {
3091 data_type = HELIOS_TYPE_VEC2;
3092 } else if constexpr (std::is_same_v<T, vec3>) {
3093 data_type = HELIOS_TYPE_VEC3;
3094 } else if constexpr (std::is_same_v<T, vec4>) {
3095 data_type = HELIOS_TYPE_VEC4;
3096 } else if constexpr (std::is_same_v<T, int2>) {
3097 data_type = HELIOS_TYPE_INT2;
3098 } else if constexpr (std::is_same_v<T, int3>) {
3099 data_type = HELIOS_TYPE_INT3;
3100 } else if constexpr (std::is_same_v<T, int4>) {
3101 data_type = HELIOS_TYPE_INT4;
3102 } 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 *>) {
3103 data_type = HELIOS_TYPE_STRING;
3104 }
3105 registerOrValidatePrimitiveDataType<T>(label, data_type);
3106 }
3107
3108 for (uint UUID: UUIDs) {
3109#ifdef HELIOS_DEBUG
3110 if (primitives.find(UUID) == primitives.end()) {
3111 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3112 }
3113#endif
3114 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3115 incrementPrimitiveDataLabelCounter(label);
3116 }
3117 }
3118
3119#ifdef USE_OPENMP
3120#pragma omp parallel for
3121#endif
3122 for (int i = 0; i < (int) UUIDs.size(); ++i) {
3123 primitives.at(UUIDs[i])->setPrimitiveData(label, data);
3124 }
3125 }
3126
3128
3134 template<typename T>
3135 void getPrimitiveData(uint UUID, const char *label, T &data) const {
3136#ifdef HELIOS_DEBUG
3137 if (primitives.find(UUID) == primitives.end()) {
3138 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3139 }
3140#endif
3141 primitives.at(UUID)->getPrimitiveData(label, data);
3142 }
3143
3145
3152 template<typename T>
3153 void getPrimitiveData(uint UUID, const char *label, std::vector<T> &data) const {
3154#ifdef HELIOS_DEBUG
3155 if (primitives.find(UUID) == primitives.end()) {
3156 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3157 }
3158#endif
3159 primitives.at(UUID)->getPrimitiveData(label, data);
3160 }
3161
3163
3169 DEPRECATED(HeliosDataType getPrimitiveDataType(uint UUID, const char *label) const);
3170
3172
3178 HeliosDataType getPrimitiveDataType(const char *label) const;
3179
3181
3186 uint getPrimitiveDataSize(uint UUID, const char *label) const;
3187
3189
3194 bool doesPrimitiveDataExist(uint UUID, const char *label) const;
3195
3197
3201 void clearPrimitiveData(uint UUID, const char *label);
3202
3204
3208 void clearPrimitiveData(const std::vector<uint> &UUIDs, const char *label);
3209
3211
3214 [[nodiscard]] std::vector<std::string> listAllPrimitiveDataLabels() const;
3215
3216
3217 //----------- VALUE-LEVEL CACHING CONFIGURATION ----------//
3218
3220
3223 void enablePrimitiveDataValueCaching(const std::string &label);
3224
3226
3229 void disablePrimitiveDataValueCaching(const std::string &label);
3230
3232
3236 [[nodiscard]] bool isPrimitiveDataValueCachingEnabled(const std::string &label) const;
3237
3239
3242 void enableObjectDataValueCaching(const std::string &label);
3243
3245
3248 void disableObjectDataValueCaching(const std::string &label);
3249
3251
3255 [[nodiscard]] bool isObjectDataValueCachingEnabled(const std::string &label) const;
3256
3257 //----------- UNIQUE VALUE QUERY METHODS ----------//
3258
3259
3261
3265 [[nodiscard]] PrimitiveType getPrimitiveType(uint UUID) const;
3266
3268
3272 void setPrimitiveParentObjectID(uint UUID, uint objID);
3273
3275
3279 void setPrimitiveParentObjectID(const std::vector<uint> &UUIDs, uint objID);
3280
3282
3285 [[nodiscard]] uint getPrimitiveParentObjectID(uint UUID) const;
3286
3288
3291 [[nodiscard]] std::vector<uint> getPrimitiveParentObjectID(const std::vector<uint> &UUIDs) const;
3292
3294
3297 [[nodiscard]] std::vector<uint> getUniquePrimitiveParentObjectIDs(const std::vector<uint> &UUIDs) const;
3298
3300
3304 [[nodiscard]] std::vector<uint> getUniquePrimitiveParentObjectIDs(const std::vector<uint> &UUIDs, bool include_ObjID_zero) const;
3305
3307
3310 [[nodiscard]] float getPrimitiveArea(uint UUID) const;
3311
3313
3318 void getPrimitiveBoundingBox(uint UUID, vec3 &min_corner, vec3 &max_corner) const;
3319
3321
3326 void getPrimitiveBoundingBox(const std::vector<uint> &UUIDs, vec3 &min_corner, vec3 &max_corner) const;
3327
3329
3332 void hideObject(uint ObjID);
3333
3335
3338 void hideObject(const std::vector<uint> &ObjIDs);
3339
3341
3344 void showObject(uint ObjID);
3345
3347
3350 void showObject(const std::vector<uint> &ObjIDs);
3351
3353
3357 [[nodiscard]] bool isObjectHidden(uint ObjID) const;
3358
3360
3363 [[nodiscard]] float getObjectArea(uint ObjID) const;
3364
3366
3369 [[nodiscard]] helios::vec3 getObjectAverageNormal(uint ObjID) const;
3370
3372
3375 [[nodiscard]] uint getObjectPrimitiveCount(uint ObjID) const;
3376
3378
3381 [[nodiscard]] helios::vec3 getObjectCenter(uint ObjID) const;
3382
3384
3388 void setObjectColor(uint ObjID, const helios::RGBcolor &color) const;
3389
3391
3395 void setObjectColor(const std::vector<uint> &ObjIDs, const helios::RGBcolor &color) const;
3396
3398
3402 void setObjectColor(uint ObjID, const helios::RGBAcolor &color) const;
3403
3405
3409 void setObjectColor(const std::vector<uint> &ObjIDs, const helios::RGBAcolor &color) const;
3410
3412
3415 [[nodiscard]] std::string getObjectTextureFile(uint ObjID) const;
3416
3418
3422 void getObjectTransformationMatrix(uint ObjID, float (&T)[16]) const;
3423
3425
3429 void setObjectTransformationMatrix(uint ObjID, float (&T)[16]) const;
3430
3432
3436 void setObjectTransformationMatrix(const std::vector<uint> &ObjIDs, float (&T)[16]) const;
3437
3439
3447 void setObjectAverageNormal(uint ObjID, const vec3 &origin, const vec3 &new_normal) const;
3448
3450
3456 void setObjectOrigin(uint ObjID, const vec3 &origin) const;
3457
3459
3462 [[nodiscard]] bool objectHasTexture(uint ObjID) const;
3463
3465
3469 [[nodiscard]] bool doesObjectContainPrimitive(uint ObjID, uint UUID) const;
3470
3472
3475 void overrideObjectTextureColor(uint ObjID) const;
3476
3478
3481 void overrideObjectTextureColor(const std::vector<uint> &ObjIDs) const;
3482
3485
3488 void useObjectTextureColor(uint ObjID) const;
3489
3492
3495 void useObjectTextureColor(const std::vector<uint> &ObjIDs);
3496
3498
3503 void getObjectBoundingBox(uint ObjID, vec3 &min_corner, vec3 &max_corner) const;
3504
3506
3511 void getObjectBoundingBox(const std::vector<uint> &ObjIDs, vec3 &min_corner, vec3 &max_corner) const;
3512
3514
3517 void printObjectInfo(uint ObjID) const;
3518
3520 [[nodiscard]] std::vector<std::string> listObjectData(uint ObjID) const;
3521
3523 [[nodiscard]] std::vector<std::string> listPrimitiveData(uint UUID) const;
3524
3526
3530 [[nodiscard]] float getPrimitiveSolidFraction(uint UUID) const;
3531
3533
3536 [[nodiscard]] helios::vec3 getPrimitiveNormal(uint UUID) const;
3537
3539
3543 void getPrimitiveTransformationMatrix(uint UUID, float (&T)[16]) const;
3544
3546
3550 void setPrimitiveTransformationMatrix(uint UUID, float (&T)[16]);
3551
3553
3557 void setPrimitiveTransformationMatrix(const std::vector<uint> &UUIDs, float (&T)[16]);
3558
3560
3563 [[nodiscard]] std::vector<helios::vec3> getPrimitiveVertices(uint UUID) const;
3564
3566
3569 [[nodiscard]] helios::RGBcolor getPrimitiveColor(uint UUID) const;
3570
3572
3575 [[nodiscard]] helios::RGBcolor getPrimitiveColorRGB(uint UUID) const;
3576
3578
3581 [[nodiscard]] helios::RGBAcolor getPrimitiveColorRGBA(uint UUID) const;
3582
3584
3588 void setPrimitiveColor(uint UUID, const helios::RGBcolor &color) const;
3589
3591
3595 void setPrimitiveColor(const std::vector<uint> &UUIDs, const helios::RGBcolor &color) const;
3596
3598
3602 void setPrimitiveColor(uint UUID, const helios::RGBAcolor &color) const;
3603
3605
3609 void setPrimitiveColor(const std::vector<uint> &UUIDs, const helios::RGBAcolor &color) const;
3610
3612
3616 [[nodiscard]] std::string getPrimitiveTextureFile(uint UUID) const;
3617
3619
3623 void setPrimitiveTextureFile(uint UUID, const std::string &texturefile) const;
3624
3626
3630 [[nodiscard]] helios::int2 getPrimitiveTextureSize(uint UUID) const;
3631
3633
3636 [[nodiscard]] std::vector<vec2> getPrimitiveTextureUV(uint UUID) const;
3637
3639
3643 [[nodiscard]] bool primitiveTextureHasTransparencyChannel(uint UUID) const;
3644
3646
3650 [[nodiscard]] const std::vector<std::vector<bool>> *getPrimitiveTextureTransparencyData(uint UUID) const;
3651
3653
3656 void overridePrimitiveTextureColor(uint UUID) const;
3657
3659
3662 void overridePrimitiveTextureColor(const std::vector<uint> &UUIDs) const;
3663
3665
3668 void usePrimitiveTextureColor(uint UUID) const;
3669
3671
3674 void usePrimitiveTextureColor(const std::vector<uint> &UUIDs) const;
3675
3677
3680 [[nodiscard]] bool isPrimitiveTextureColorOverridden(uint UUID) const;
3681
3683
3686 void printPrimitiveInfo(uint UUID) const;
3687
3688 //-------- Compound Object Data Methods ---------- //
3689
3691
3697 template<typename T>
3698 void setObjectData(uint objID, const char *label, const T &data) {
3699#ifdef HELIOS_DEBUG
3700 if (objects.find(objID) == objects.end()) {
3701 helios_runtime_error("ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
3702 }
3703#endif
3704 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> ||
3705 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 *>,
3706 "Context::setObjectData() was called with an unsupported type.");
3707
3708 // Validate data type consistency and register/validate type
3709 HeliosDataType data_type;
3710 if constexpr (std::is_same_v<T, int>) {
3711 data_type = HELIOS_TYPE_INT;
3712 } else if constexpr (std::is_same_v<T, uint>) {
3713 data_type = HELIOS_TYPE_UINT;
3714 } else if constexpr (std::is_same_v<T, float>) {
3715 data_type = HELIOS_TYPE_FLOAT;
3716 } else if constexpr (std::is_same_v<T, double>) {
3717 data_type = HELIOS_TYPE_DOUBLE;
3718 } else if constexpr (std::is_same_v<T, vec2>) {
3719 data_type = HELIOS_TYPE_VEC2;
3720 } else if constexpr (std::is_same_v<T, vec3>) {
3721 data_type = HELIOS_TYPE_VEC3;
3722 } else if constexpr (std::is_same_v<T, vec4>) {
3723 data_type = HELIOS_TYPE_VEC4;
3724 } else if constexpr (std::is_same_v<T, int2>) {
3725 data_type = HELIOS_TYPE_INT2;
3726 } else if constexpr (std::is_same_v<T, int3>) {
3727 data_type = HELIOS_TYPE_INT3;
3728 } else if constexpr (std::is_same_v<T, int4>) {
3729 data_type = HELIOS_TYPE_INT4;
3730 } 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 *>) {
3731 data_type = HELIOS_TYPE_STRING;
3732 }
3733 registerOrValidateObjectDataType<T>(label, data_type);
3734
3735 // Check if this object already has cached data for registry maintenance
3736 std::string label_str = std::string(label);
3737 bool had_cached_value = false;
3738
3739 // Handle caching only for supported types, and avoid character arrays
3740 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3741 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
3742 T old_cached_value{};
3743 objects.at(objID)->getObjectData(label, old_cached_value);
3744 decrementObjectValueRegistry(label_str, old_cached_value);
3745 had_cached_value = true;
3746 }
3747 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3748 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
3749 std::string old_cached_value;
3750 objects.at(objID)->getObjectData(label, old_cached_value);
3751 decrementObjectValueRegistry(label_str, old_cached_value);
3752 had_cached_value = true;
3753 }
3754 }
3755
3756 if (!objects.at(objID)->doesObjectDataExist(label)) {
3757 incrementObjectDataLabelCounter(label);
3758 }
3759 objects.at(objID)->setObjectData(label, data);
3760
3761 // Update value registry if caching is enabled for this label (only for new data)
3762 if (isObjectDataValueCachingEnabled(label_str) && !had_cached_value) {
3763 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3764 incrementObjectValueRegistry(label_str, data);
3765 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3766 incrementObjectValueRegistry(label_str, std::string(data));
3767 }
3768 } else if (isObjectDataValueCachingEnabled(label_str) && had_cached_value) {
3769 // For updates, just add the new value (old value was already decremented)
3770 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3771 incrementObjectValueRegistry(label_str, data);
3772 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3773 incrementObjectValueRegistry(label_str, std::string(data));
3774 }
3775 }
3776 }
3777
3779
3785 template<typename T>
3786 void setObjectData(const std::vector<uint> &objIDs, const char *label, const T &data) {
3787 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> ||
3788 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 *>,
3789 "Context::setObjectData() was called with an unsupported type.");
3790
3791 // Validate data type consistency and register/validate type
3792 if (!objIDs.empty()) {
3793 HeliosDataType data_type;
3794 if constexpr (std::is_same_v<T, int>) {
3795 data_type = HELIOS_TYPE_INT;
3796 } else if constexpr (std::is_same_v<T, uint>) {
3797 data_type = HELIOS_TYPE_UINT;
3798 } else if constexpr (std::is_same_v<T, float>) {
3799 data_type = HELIOS_TYPE_FLOAT;
3800 } else if constexpr (std::is_same_v<T, double>) {
3801 data_type = HELIOS_TYPE_DOUBLE;
3802 } else if constexpr (std::is_same_v<T, vec2>) {
3803 data_type = HELIOS_TYPE_VEC2;
3804 } else if constexpr (std::is_same_v<T, vec3>) {
3805 data_type = HELIOS_TYPE_VEC3;
3806 } else if constexpr (std::is_same_v<T, vec4>) {
3807 data_type = HELIOS_TYPE_VEC4;
3808 } else if constexpr (std::is_same_v<T, int2>) {
3809 data_type = HELIOS_TYPE_INT2;
3810 } else if constexpr (std::is_same_v<T, int3>) {
3811 data_type = HELIOS_TYPE_INT3;
3812 } else if constexpr (std::is_same_v<T, int4>) {
3813 data_type = HELIOS_TYPE_INT4;
3814 } 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 *>) {
3815 data_type = HELIOS_TYPE_STRING;
3816 }
3817 registerOrValidateObjectDataType<T>(label, data_type);
3818 }
3819
3820 // Check if caching is enabled for this label
3821 std::string label_str = std::string(label);
3822 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
3823
3824 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
3825 if (caching_enabled) {
3826 // Handle caching only for supported types
3827 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3828 for (uint objID: objIDs) {
3829 if (objects.at(objID)->doesObjectDataExist(label)) {
3830 T old_cached_value{};
3831 objects.at(objID)->getObjectData(label, old_cached_value);
3832 decrementObjectValueRegistry(label_str, old_cached_value);
3833 }
3834 }
3835 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3836 for (uint objID: objIDs) {
3837 if (objects.at(objID)->doesObjectDataExist(label)) {
3838 std::string old_cached_value;
3839 objects.at(objID)->getObjectData(label, old_cached_value);
3840 decrementObjectValueRegistry(label_str, old_cached_value);
3841 }
3842 }
3843 }
3844 }
3845
3846 // Count new data labels
3847 for (uint objID: objIDs) {
3848 if (!objects.at(objID)->doesObjectDataExist(label)) {
3849 incrementObjectDataLabelCounter(label);
3850 }
3851 }
3852
3853#ifdef USE_OPENMP
3854#pragma omp parallel for
3855#endif
3856 for (int i = 0; i < (int) objIDs.size(); ++i) {
3857 objects.at(objIDs[i])->setObjectData(label, data);
3858 }
3859
3860 // Update value registry if caching is enabled (increment the new value for all objects)
3861 if (caching_enabled) {
3862 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3863 // Increment the new value once for each object that received it
3864 for (size_t i = 0; i < objIDs.size(); ++i) {
3865 incrementObjectValueRegistry(label_str, data);
3866 }
3867 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3868 // Increment the new value once for each object that received it
3869 for (size_t i = 0; i < objIDs.size(); ++i) {
3870 incrementObjectValueRegistry(label_str, std::string(data));
3871 }
3872 }
3873 }
3874 }
3875
3877
3883 template<typename T>
3884 void setObjectData(const std::vector<std::vector<uint>> &objIDs, const char *label, const T &data) {
3885 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> ||
3886 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 *>,
3887 "Context::setObjectData() was called with an unsupported type.");
3888
3889 // Validate data type consistency and register/validate type
3890 if (!objIDs.empty() && !objIDs[0].empty()) {
3891 HeliosDataType data_type;
3892 if constexpr (std::is_same_v<T, int>) {
3893 data_type = HELIOS_TYPE_INT;
3894 } else if constexpr (std::is_same_v<T, uint>) {
3895 data_type = HELIOS_TYPE_UINT;
3896 } else if constexpr (std::is_same_v<T, float>) {
3897 data_type = HELIOS_TYPE_FLOAT;
3898 } else if constexpr (std::is_same_v<T, double>) {
3899 data_type = HELIOS_TYPE_DOUBLE;
3900 } else if constexpr (std::is_same_v<T, vec2>) {
3901 data_type = HELIOS_TYPE_VEC2;
3902 } else if constexpr (std::is_same_v<T, vec3>) {
3903 data_type = HELIOS_TYPE_VEC3;
3904 } else if constexpr (std::is_same_v<T, vec4>) {
3905 data_type = HELIOS_TYPE_VEC4;
3906 } else if constexpr (std::is_same_v<T, int2>) {
3907 data_type = HELIOS_TYPE_INT2;
3908 } else if constexpr (std::is_same_v<T, int3>) {
3909 data_type = HELIOS_TYPE_INT3;
3910 } else if constexpr (std::is_same_v<T, int4>) {
3911 data_type = HELIOS_TYPE_INT4;
3912 } 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 *>) {
3913 data_type = HELIOS_TYPE_STRING;
3914 }
3915 registerOrValidateObjectDataType<T>(label, data_type);
3916 }
3917
3918 // Check if caching is enabled for this label
3919 std::string label_str = std::string(label);
3920 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
3921 size_t total_objects = 0;
3922
3923 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
3924 if (caching_enabled) {
3925 // Handle caching only for supported types
3926 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3927 for (const auto &j: objIDs) {
3928 for (uint objID: j) {
3929 total_objects++;
3930 if (objects.at(objID)->doesObjectDataExist(label)) {
3931 T old_cached_value{};
3932 objects.at(objID)->getObjectData(label, old_cached_value);
3933 decrementObjectValueRegistry(label_str, old_cached_value);
3934 }
3935 }
3936 }
3937 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3938 for (const auto &j: objIDs) {
3939 for (uint objID: j) {
3940 total_objects++;
3941 if (objects.at(objID)->doesObjectDataExist(label)) {
3942 std::string old_cached_value;
3943 objects.at(objID)->getObjectData(label, old_cached_value);
3944 decrementObjectValueRegistry(label_str, old_cached_value);
3945 }
3946 }
3947 }
3948 }
3949 } else {
3950 // Count total objects for later cache increment
3951 for (const auto &j: objIDs) {
3952 total_objects += j.size();
3953 }
3954 }
3955
3956 for (const auto &j: objIDs) {
3957 for (uint objID: j) {
3958 if (!objects.at(objID)->doesObjectDataExist(label)) {
3959 incrementObjectDataLabelCounter(label);
3960 }
3961 }
3962 }
3963
3964#ifdef USE_OPENMP
3965#pragma omp parallel for
3966#endif
3967 for (int j = 0; j < (int) objIDs.size(); ++j) {
3968 for (size_t i = 0; i < objIDs[j].size(); ++i) {
3969 objects.at(objIDs[j][i])->setObjectData(label, data);
3970 }
3971 }
3972
3973 // Update value registry if caching is enabled (increment the new value for all objects)
3974 if (caching_enabled) {
3975 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3976 // Increment the new value once for each object that received it
3977 for (size_t i = 0; i < total_objects; ++i) {
3978 incrementObjectValueRegistry(label_str, data);
3979 }
3980 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3981 // Increment the new value once for each object that received it
3982 for (size_t i = 0; i < total_objects; ++i) {
3983 incrementObjectValueRegistry(label_str, std::string(data));
3984 }
3985 }
3986 }
3987 }
3988
3990
3996 template<typename T>
3997 void setObjectData(const std::vector<std::vector<std::vector<uint>>> &objIDs, const char *label, const T &data) {
3998 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> ||
3999 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 *>,
4000 "Context::setObjectData() was called with an unsupported type.");
4001
4002 // Validate data type consistency and register/validate type
4003 if (!objIDs.empty() && !objIDs[0].empty() && !objIDs[0][0].empty()) {
4004 HeliosDataType data_type;
4005 if constexpr (std::is_same_v<T, int>) {
4006 data_type = HELIOS_TYPE_INT;
4007 } else if constexpr (std::is_same_v<T, uint>) {
4008 data_type = HELIOS_TYPE_UINT;
4009 } else if constexpr (std::is_same_v<T, float>) {
4010 data_type = HELIOS_TYPE_FLOAT;
4011 } else if constexpr (std::is_same_v<T, double>) {
4012 data_type = HELIOS_TYPE_DOUBLE;
4013 } else if constexpr (std::is_same_v<T, vec2>) {
4014 data_type = HELIOS_TYPE_VEC2;
4015 } else if constexpr (std::is_same_v<T, vec3>) {
4016 data_type = HELIOS_TYPE_VEC3;
4017 } else if constexpr (std::is_same_v<T, vec4>) {
4018 data_type = HELIOS_TYPE_VEC4;
4019 } else if constexpr (std::is_same_v<T, int2>) {
4020 data_type = HELIOS_TYPE_INT2;
4021 } else if constexpr (std::is_same_v<T, int3>) {
4022 data_type = HELIOS_TYPE_INT3;
4023 } else if constexpr (std::is_same_v<T, int4>) {
4024 data_type = HELIOS_TYPE_INT4;
4025 } 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 *>) {
4026 data_type = HELIOS_TYPE_STRING;
4027 }
4028 registerOrValidateObjectDataType<T>(label, data_type);
4029 }
4030
4031 // Check if caching is enabled for this label
4032 std::string label_str = std::string(label);
4033 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
4034 size_t total_objects = 0;
4035
4036 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
4037 if (caching_enabled) {
4038 // Handle caching only for supported types
4039 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4040 for (const auto &k: objIDs) {
4041 for (const auto &j: k) {
4042 for (uint objID: j) {
4043 total_objects++;
4044 if (objects.at(objID)->doesObjectDataExist(label)) {
4045 T old_cached_value{};
4046 objects.at(objID)->getObjectData(label, old_cached_value);
4047 decrementObjectValueRegistry(label_str, old_cached_value);
4048 }
4049 }
4050 }
4051 }
4052 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4053 for (const auto &k: objIDs) {
4054 for (const auto &j: k) {
4055 for (uint objID: j) {
4056 total_objects++;
4057 if (objects.at(objID)->doesObjectDataExist(label)) {
4058 std::string old_cached_value;
4059 objects.at(objID)->getObjectData(label, old_cached_value);
4060 decrementObjectValueRegistry(label_str, old_cached_value);
4061 }
4062 }
4063 }
4064 }
4065 }
4066 } else {
4067 // Count total objects for later cache increment
4068 for (const auto &k: objIDs) {
4069 for (const auto &j: k) {
4070 total_objects += j.size();
4071 }
4072 }
4073 }
4074
4075 for (const auto &k: objIDs) {
4076 for (const auto &j: k) {
4077 for (uint objID: j) {
4078 if (!objects.at(objID)->doesObjectDataExist(label)) {
4079 incrementObjectDataLabelCounter(label);
4080 }
4081 }
4082 }
4083 }
4084
4085#ifdef USE_OPENMP
4086#pragma omp parallel for
4087#endif
4088 for (int k = 0; k < (int) objIDs.size(); ++k) {
4089 for (size_t j = 0; j < objIDs[k].size(); ++j) {
4090 for (size_t i = 0; i < objIDs[k][j].size(); ++i) {
4091 uint objID = objIDs[k][j][i];
4092 objects.at(objID)->setObjectData(label, data);
4093 }
4094 }
4095 }
4096
4097 // Update value registry if caching is enabled (increment the new value for all objects)
4098 if (caching_enabled) {
4099 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4100 // Increment the new value once for each object that received it
4101 for (size_t i = 0; i < total_objects; ++i) {
4102 incrementObjectValueRegistry(label_str, data);
4103 }
4104 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4105 // Increment the new value once for each object that received it
4106 for (size_t i = 0; i < total_objects; ++i) {
4107 incrementObjectValueRegistry(label_str, std::string(data));
4108 }
4109 }
4110 }
4111 }
4112
4114
4121 template<typename T>
4122 void setObjectData(uint objID, const char *label, const std::vector<T> &data) {
4123#ifdef HELIOS_DEBUG
4124 if (objects.find(objID) == objects.end()) {
4125 helios_runtime_error("ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
4126 }
4127#endif
4128 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> ||
4129 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 *>,
4130 "Context::setObjectData() was called with an unsupported type.");
4131
4132 // Validate data type consistency and register/validate type
4133 HeliosDataType data_type;
4134 if constexpr (std::is_same_v<T, int>) {
4135 data_type = HELIOS_TYPE_INT;
4136 } else if constexpr (std::is_same_v<T, uint>) {
4137 data_type = HELIOS_TYPE_UINT;
4138 } else if constexpr (std::is_same_v<T, float>) {
4139 data_type = HELIOS_TYPE_FLOAT;
4140 } else if constexpr (std::is_same_v<T, double>) {
4141 data_type = HELIOS_TYPE_DOUBLE;
4142 } else if constexpr (std::is_same_v<T, vec2>) {
4143 data_type = HELIOS_TYPE_VEC2;
4144 } else if constexpr (std::is_same_v<T, vec3>) {
4145 data_type = HELIOS_TYPE_VEC3;
4146 } else if constexpr (std::is_same_v<T, vec4>) {
4147 data_type = HELIOS_TYPE_VEC4;
4148 } else if constexpr (std::is_same_v<T, int2>) {
4149 data_type = HELIOS_TYPE_INT2;
4150 } else if constexpr (std::is_same_v<T, int3>) {
4151 data_type = HELIOS_TYPE_INT3;
4152 } else if constexpr (std::is_same_v<T, int4>) {
4153 data_type = HELIOS_TYPE_INT4;
4154 } 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 *>) {
4155 data_type = HELIOS_TYPE_STRING;
4156 }
4157 registerOrValidateObjectDataType<T>(label, data_type);
4158
4159 objects.at(objID)->setObjectData(label, data);
4160 }
4161
4163
4170 template<typename T>
4171 void setObjectData(const std::vector<uint> &objIDs, const char *label, const std::vector<T> &data) {
4172#ifdef HELIOS_DEBUG
4173 if (objIDs.size() != data.size()) {
4174 helios_runtime_error("ERROR (Context::setObjectData): Object IDs and data vectors must be the same size.");
4175 }
4176#endif
4177 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> ||
4178 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 *>,
4179 "Context::setObjectData() was called with an unsupported type.");
4180
4181 // Validate data type consistency and register/validate type
4182 if (!objIDs.empty()) {
4183 HeliosDataType data_type;
4184 if constexpr (std::is_same_v<T, int>) {
4185 data_type = HELIOS_TYPE_INT;
4186 } else if constexpr (std::is_same_v<T, uint>) {
4187 data_type = HELIOS_TYPE_UINT;
4188 } else if constexpr (std::is_same_v<T, float>) {
4189 data_type = HELIOS_TYPE_FLOAT;
4190 } else if constexpr (std::is_same_v<T, double>) {
4191 data_type = HELIOS_TYPE_DOUBLE;
4192 } else if constexpr (std::is_same_v<T, vec2>) {
4193 data_type = HELIOS_TYPE_VEC2;
4194 } else if constexpr (std::is_same_v<T, vec3>) {
4195 data_type = HELIOS_TYPE_VEC3;
4196 } else if constexpr (std::is_same_v<T, vec4>) {
4197 data_type = HELIOS_TYPE_VEC4;
4198 } else if constexpr (std::is_same_v<T, int2>) {
4199 data_type = HELIOS_TYPE_INT2;
4200 } else if constexpr (std::is_same_v<T, int3>) {
4201 data_type = HELIOS_TYPE_INT3;
4202 } else if constexpr (std::is_same_v<T, int4>) {
4203 data_type = HELIOS_TYPE_INT4;
4204 } 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 *>) {
4205 data_type = HELIOS_TYPE_STRING;
4206 }
4207 registerOrValidateObjectDataType<T>(label, data_type);
4208 }
4209
4210 for (uint objID: objIDs) {
4211 if (!objects.at(objID)->doesObjectDataExist(label)) {
4212 incrementObjectDataLabelCounter(label);
4213 }
4214 }
4215
4216#ifdef USE_OPENMP
4217#pragma omp parallel for
4218#endif
4219 for (int i = 0; i < (int) objIDs.size(); ++i) {
4220 objects.at(objIDs[i])->setObjectData(label, data[i]);
4221 }
4222 }
4223
4225
4231 template<typename T>
4232 void getObjectData(uint objID, const char *label, T &data) const {
4233#ifdef HELIOS_DEBUG
4234 if (objects.find(objID) == objects.end()) {
4235 helios_runtime_error("ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
4236 }
4237#endif
4238 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> ||
4239 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 *>,
4240 "Context::getObjectData() was called with an unsupported type.");
4241 objects.at(objID)->getObjectData(label, data);
4242 }
4243
4245
4252 template<typename T>
4253 void getObjectData(uint objID, const char *label, std::vector<T> &data) const {
4254#ifdef HELIOS_DEBUG
4255 if (objects.find(objID) == objects.end()) {
4256 helios_runtime_error("ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
4257 }
4258#endif
4259 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> ||
4260 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 *>,
4261 "Context::getObjectData() was called with an unsupported type.");
4262 objects.at(objID)->getObjectData(label, data);
4263 }
4264
4266
4272 DEPRECATED(HeliosDataType getObjectDataType(uint objID, const char *label) const);
4273
4275
4281 HeliosDataType getObjectDataType(const char *label) const;
4282
4284
4289 uint getObjectDataSize(uint objID, const char *label) const;
4290
4292
4297 bool doesObjectDataExist(uint objID, const char *label) const;
4298
4300
4304 void clearObjectData(uint objID, const char *label);
4305
4307
4311 void clearObjectData(const std::vector<uint> &objIDs, const char *label);
4312
4314
4317 [[nodiscard]] std::vector<std::string> listAllObjectDataLabels() const;
4318
4320
4324 [[nodiscard]] bool areObjectPrimitivesComplete(uint objID) const;
4325
4327
4330 void cleanDeletedObjectIDs(std::vector<uint> &objIDs) const;
4331
4333
4336 void cleanDeletedObjectIDs(std::vector<std::vector<uint>> &objIDs) const;
4337
4339
4342 void cleanDeletedObjectIDs(std::vector<std::vector<std::vector<uint>>> &objIDs) const;
4343
4344 //-------- Global Data Methods ---------- //
4345
4347
4351 template<typename T>
4352 void setGlobalData(const char *label, const T &data) {
4353 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> ||
4354 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>,
4355 "Context::setGlobalData() was called with an unsupported type.");
4356
4357 globaldata[label].size = 1;
4358 if constexpr (std::is_same_v<T, int>) {
4359 globaldata[label].global_data_int = {data};
4360 globaldata[label].type = HELIOS_TYPE_INT;
4361 } else if constexpr (std::is_same_v<T, uint>) {
4362 globaldata[label].global_data_uint = {data};
4363 globaldata[label].type = HELIOS_TYPE_UINT;
4364 } else if constexpr (std::is_same_v<T, float>) {
4365 globaldata[label].global_data_float = {data};
4366 globaldata[label].type = HELIOS_TYPE_FLOAT;
4367 } else if constexpr (std::is_same_v<T, double>) {
4368 globaldata[label].global_data_double = {data};
4369 globaldata[label].type = HELIOS_TYPE_DOUBLE;
4370 } else if constexpr (std::is_same_v<T, vec2>) {
4371 globaldata[label].global_data_vec2 = {data};
4372 globaldata[label].type = HELIOS_TYPE_VEC2;
4373 } else if constexpr (std::is_same_v<T, vec3>) {
4374 globaldata[label].global_data_vec3 = {data};
4375 globaldata[label].type = HELIOS_TYPE_VEC3;
4376 } else if constexpr (std::is_same_v<T, vec4>) {
4377 globaldata[label].global_data_vec4 = {data};
4378 globaldata[label].type = HELIOS_TYPE_VEC4;
4379 } else if constexpr (std::is_same_v<T, int2>) {
4380 globaldata[label].global_data_int2 = {data};
4381 globaldata[label].type = HELIOS_TYPE_INT2;
4382 } else if constexpr (std::is_same_v<T, int3>) {
4383 globaldata[label].global_data_int3 = {data};
4384 globaldata[label].type = HELIOS_TYPE_INT3;
4385 } else if constexpr (std::is_same_v<T, int4>) {
4386 globaldata[label].global_data_int4 = {data};
4387 globaldata[label].type = HELIOS_TYPE_INT4;
4388 } 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 *>) {
4389 globaldata[label].global_data_string = {data};
4390 globaldata[label].type = HELIOS_TYPE_STRING;
4391 } else if constexpr (std::is_same_v<T, bool>) {
4392 globaldata[label].global_data_bool = {data};
4393 globaldata[label].type = HELIOS_TYPE_BOOL;
4394 }
4395 }
4396
4398
4402 template<typename T>
4403 void setGlobalData(const char *label, const std::vector<T> &data) {
4404 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> ||
4405 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>,
4406 "Context::setGlobalData() was called with an unsupported type.");
4407
4408 globaldata[label].size = data.size();
4409 if constexpr (std::is_same_v<T, int>) {
4410 globaldata[label].global_data_int = data;
4411 globaldata[label].type = HELIOS_TYPE_INT;
4412 } else if constexpr (std::is_same_v<T, uint>) {
4413 globaldata[label].global_data_uint = data;
4414 globaldata[label].type = HELIOS_TYPE_UINT;
4415 } else if constexpr (std::is_same_v<T, float>) {
4416 globaldata[label].global_data_float = data;
4417 globaldata[label].type = HELIOS_TYPE_FLOAT;
4418 } else if constexpr (std::is_same_v<T, double>) {
4419 globaldata[label].global_data_double = data;
4420 globaldata[label].type = HELIOS_TYPE_DOUBLE;
4421 } else if constexpr (std::is_same_v<T, vec2>) {
4422 globaldata[label].global_data_vec2 = data;
4423 globaldata[label].type = HELIOS_TYPE_VEC2;
4424 } else if constexpr (std::is_same_v<T, vec3>) {
4425 globaldata[label].global_data_vec3 = data;
4426 globaldata[label].type = HELIOS_TYPE_VEC3;
4427 } else if constexpr (std::is_same_v<T, vec4>) {
4428 globaldata[label].global_data_vec4 = data;
4429 globaldata[label].type = HELIOS_TYPE_VEC4;
4430 } else if constexpr (std::is_same_v<T, int2>) {
4431 globaldata[label].global_data_int2 = data;
4432 globaldata[label].type = HELIOS_TYPE_INT2;
4433 } else if constexpr (std::is_same_v<T, int3>) {
4434 globaldata[label].global_data_int3 = data;
4435 globaldata[label].type = HELIOS_TYPE_INT3;
4436 } else if constexpr (std::is_same_v<T, int4>) {
4437 globaldata[label].global_data_int4 = data;
4438 globaldata[label].type = HELIOS_TYPE_INT4;
4439 } 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 *>) {
4440 globaldata[label].global_data_string = data;
4441 globaldata[label].type = HELIOS_TYPE_STRING;
4442 } else if constexpr (std::is_same_v<T, bool>) {
4443 globaldata[label].global_data_bool = data;
4444 globaldata[label].type = HELIOS_TYPE_BOOL;
4445 }
4446 }
4447
4449
4453 template<typename T>
4454 void getGlobalData(const char *label, T &data) const {
4455 // Use SFINAE to detect if T is std::vector<U> for some U
4456 if constexpr (std::is_same_v<T, std::vector<int>>) {
4457 // Vector case for int
4458 if (globaldata.at(label).type == HELIOS_TYPE_INT) {
4459 data = globaldata.at(label).global_data_int;
4460 } else {
4461 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) + " does not have type int.");
4462 }
4463 } else if constexpr (std::is_same_v<T, std::vector<uint>>) {
4464 // Vector case for uint
4465 if (globaldata.at(label).type == HELIOS_TYPE_UINT) {
4466 data = globaldata.at(label).global_data_uint;
4467 } else {
4468 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) + " does not have type uint.");
4469 }
4470 } else if constexpr (std::is_same_v<T, std::vector<float>>) {
4471 // Vector case for float
4472 if (globaldata.at(label).type == HELIOS_TYPE_FLOAT) {
4473 data = globaldata.at(label).global_data_float;
4474 } else {
4475 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) + " does not have type float.");
4476 }
4477 } else if constexpr (std::is_same_v<T, std::vector<double>>) {
4478 // Vector case for double
4479 if (globaldata.at(label).type == HELIOS_TYPE_DOUBLE) {
4480 data = globaldata.at(label).global_data_double;
4481 } else {
4482 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) + " does not have type double.");
4483 }
4484 } else if constexpr (std::is_same_v<T, std::vector<vec2>>) {
4485 // Vector case for vec2
4486 if (globaldata.at(label).type == HELIOS_TYPE_VEC2) {
4487 data = globaldata.at(label).global_data_vec2;
4488 } else {
4489 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) + " does not have type vec2.");
4490 }
4491 } else if constexpr (std::is_same_v<T, std::vector<vec3>>) {
4492 // Vector case for vec3
4493 if (globaldata.at(label).type == HELIOS_TYPE_VEC3) {
4494 data = globaldata.at(label).global_data_vec3;
4495 } else {
4496 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) + " does not have type vec3.");
4497 }
4498 } else if constexpr (std::is_same_v<T, std::vector<vec4>>) {
4499 // Vector case for vec4
4500 if (globaldata.at(label).type == HELIOS_TYPE_VEC4) {
4501 data = globaldata.at(label).global_data_vec4;
4502 } else {
4503 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) + " does not have type vec4.");
4504 }
4505 } else if constexpr (std::is_same_v<T, std::vector<int2>>) {
4506 // Vector case for int2
4507 if (globaldata.at(label).type == HELIOS_TYPE_INT2) {
4508 data = globaldata.at(label).global_data_int2;
4509 } else {
4510 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) + " does not have type int2.");
4511 }
4512 } else if constexpr (std::is_same_v<T, std::vector<int3>>) {
4513 // Vector case for int3
4514 if (globaldata.at(label).type == HELIOS_TYPE_INT3) {
4515 data = globaldata.at(label).global_data_int3;
4516 } else {
4517 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) + " does not have type int3.");
4518 }
4519 } else if constexpr (std::is_same_v<T, std::vector<int4>>) {
4520 // Vector case for int4
4521 if (globaldata.at(label).type == HELIOS_TYPE_INT4) {
4522 data = globaldata.at(label).global_data_int4;
4523 } else {
4524 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) + " does not have type int4.");
4525 }
4526 } else if constexpr (std::is_same_v<T, std::vector<std::string>>) {
4527 // Vector case for string
4528 if (globaldata.at(label).type == HELIOS_TYPE_STRING) {
4529 data = globaldata.at(label).global_data_string;
4530 } else {
4531 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) + " does not have type string.");
4532 }
4533 } else if constexpr (std::is_same_v<T, int>) {
4534 // Scalar case for int
4535 if (globaldata.at(label).type == HELIOS_TYPE_INT) {
4536 data = globaldata.at(label).global_data_int.front();
4537 } else {
4538 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) + " does not have type int.");
4539 }
4540 } else if constexpr (std::is_same_v<T, uint>) {
4541 // Scalar case for uint
4542 if (globaldata.at(label).type == HELIOS_TYPE_UINT) {
4543 data = globaldata.at(label).global_data_uint.front();
4544 } else {
4545 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) + " does not have type uint.");
4546 }
4547 } else if constexpr (std::is_same_v<T, float>) {
4548 // Scalar case for float
4549 if (globaldata.at(label).type == HELIOS_TYPE_FLOAT) {
4550 data = globaldata.at(label).global_data_float.front();
4551 } else {
4552 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) + " does not have type float.");
4553 }
4554 } else if constexpr (std::is_same_v<T, double>) {
4555 // Scalar case for double
4556 if (globaldata.at(label).type == HELIOS_TYPE_DOUBLE) {
4557 data = globaldata.at(label).global_data_double.front();
4558 } else {
4559 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) + " does not have type double.");
4560 }
4561 } else if constexpr (std::is_same_v<T, vec2>) {
4562 // Scalar case for vec2
4563 if (globaldata.at(label).type == HELIOS_TYPE_VEC2) {
4564 data = globaldata.at(label).global_data_vec2.front();
4565 } else {
4566 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) + " does not have type vec2.");
4567 }
4568 } else if constexpr (std::is_same_v<T, vec3>) {
4569 // Scalar case for vec3
4570 if (globaldata.at(label).type == HELIOS_TYPE_VEC3) {
4571 data = globaldata.at(label).global_data_vec3.front();
4572 } else {
4573 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) + " does not have type vec3.");
4574 }
4575 } else if constexpr (std::is_same_v<T, vec4>) {
4576 // Scalar case for vec4
4577 if (globaldata.at(label).type == HELIOS_TYPE_VEC4) {
4578 data = globaldata.at(label).global_data_vec4.front();
4579 } else {
4580 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) + " does not have type vec4.");
4581 }
4582 } else if constexpr (std::is_same_v<T, int2>) {
4583 // Scalar case for int2
4584 if (globaldata.at(label).type == HELIOS_TYPE_INT2) {
4585 data = globaldata.at(label).global_data_int2.front();
4586 } else {
4587 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) + " does not have type int2.");
4588 }
4589 } else if constexpr (std::is_same_v<T, int3>) {
4590 // Scalar case for int3
4591 if (globaldata.at(label).type == HELIOS_TYPE_INT3) {
4592 data = globaldata.at(label).global_data_int3.front();
4593 } else {
4594 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) + " does not have type int3.");
4595 }
4596 } else if constexpr (std::is_same_v<T, int4>) {
4597 // Scalar case for int4
4598 if (globaldata.at(label).type == HELIOS_TYPE_INT4) {
4599 data = globaldata.at(label).global_data_int4.front();
4600 } else {
4601 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) + " does not have type int4.");
4602 }
4603 } 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 *>) {
4604 // Scalar case for string
4605 if (globaldata.at(label).type == HELIOS_TYPE_STRING) {
4606 data = globaldata.at(label).global_data_string.front();
4607 } else {
4608 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) + " does not have type string.");
4609 }
4610 } else if constexpr (std::is_same_v<T, bool>) {
4611 // Scalar case for bool
4612 if (globaldata.at(label).type == HELIOS_TYPE_BOOL) {
4613 data = globaldata.at(label).global_data_bool.front();
4614 } else {
4615 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type bool, but data " + std::string(label) + " does not have type bool.");
4616 }
4617 } else {
4618 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> ||
4619 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 *> ||
4620 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>> ||
4621 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>> ||
4622 std::is_same_v<T, std::vector<std::string>> || std::is_same_v<T, std::vector<bool>>,
4623 "CompoundObject::getGlobalData() was called with an unsupported type.");
4624 }
4625 }
4626
4628
4632 void renameGlobalData(const char *old_label, const char *new_label);
4633
4635
4639 void duplicateGlobalData(const char *old_label, const char *new_label);
4640
4642
4645 void clearGlobalData(const char *label);
4646
4648
4652 HeliosDataType getGlobalDataType(const char *label) const;
4653
4655
4659 size_t getGlobalDataSize(const char *label) const;
4660
4662
4665 [[nodiscard]] std::vector<std::string> listGlobalData() const;
4666
4668
4672 bool doesGlobalDataExist(const char *label) const;
4673
4675
4680 void incrementGlobalData(const char *label, int increment);
4681
4683
4688 void incrementGlobalData(const char *label, uint increment);
4689
4691
4696 void incrementGlobalData(const char *label, float increment);
4697
4699
4704 void incrementGlobalData(const char *label, double increment);
4705
4706 //--------- Compound Objects Methods -------------//
4707
4709
4712 [[nodiscard]] CompoundObject *getObjectPointer(uint ObjID) const;
4713
4715
4718 [[nodiscard]] uint getObjectCount() const;
4719
4721
4724 [[nodiscard]] bool doesObjectExist(uint ObjID) const;
4725
4727
4730 [[nodiscard]] std::vector<uint> getAllObjectIDs() const;
4731
4733
4736 void deleteObject(uint ObjID);
4737
4739
4742 void deleteObject(const std::vector<uint> &ObjIDs);
4743
4745
4749 uint copyObject(uint ObjID);
4750
4752
4756 std::vector<uint> copyObject(const std::vector<uint> &ObjIDs);
4757
4759
4763 void copyObjectData(uint source_objID, uint destination_objID);
4764
4766
4771 void duplicateObjectData(uint objID, const char *old_label, const char *new_label);
4772
4774
4779 void renameObjectData(uint objID, const char *old_label, const char *new_label);
4780
4782
4788 std::vector<uint> filterObjectsByData(const std::vector<uint> &ObjIDs, const char *object_data, float threshold, const char *comparator) const;
4789
4791
4795 void translateObject(uint ObjID, const vec3 &shift) const;
4796
4798
4802 void translateObject(const std::vector<uint> &ObjIDs, const vec3 &shift) const;
4803
4805
4810 void rotateObject(uint ObjID, float rotation_radians, const char *rotation_axis_xyz) const;
4811
4813
4818 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const char *rotation_axis_xyz) const;
4819
4821
4826 void rotateObject(uint ObjID, float rotation_radians, const vec3 &rotation_axis_vector) const;
4827
4829
4834 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_axis_vector) const;
4835
4837
4843 void rotateObject(uint ObjID, float rotation_radians, const vec3 &rotation_origin, const vec3 &rotation_axis_vector) const;
4844
4846
4852 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_origin, const vec3 &rotation_axis_vector) const;
4853
4855
4860 void rotateObjectAboutOrigin(uint ObjID, float rotation_radians, const vec3 &rotation_axis_vector) const;
4861
4863
4868 void rotateObjectAboutOrigin(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_axis_vector) const;
4869
4871
4875 void scaleObject(uint ObjID, const helios::vec3 &scalefact) const;
4876
4878
4882 void scaleObject(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
4883
4885
4889 void scaleObjectAboutCenter(uint ObjID, const helios::vec3 &scalefact) const;
4890
4892
4896 void scaleObjectAboutCenter(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
4897
4899
4904 void scaleObjectAboutPoint(uint ObjID, const helios::vec3 &scalefact, const helios::vec3 &point) const;
4905
4907
4912 void scaleObjectAboutPoint(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact, const helios::vec3 &point) const;
4913
4915
4920 void scaleObjectAboutOrigin(uint ObjID, const helios::vec3 &scalefact) const;
4921
4923
4928 void scaleObjectAboutOrigin(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
4929
4931
4934 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(uint ObjID) const;
4935
4937
4940 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(const std::vector<uint> &ObjIDs) const;
4941
4943
4946 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(const std::vector<std::vector<uint>> &ObjIDs) const;
4947
4949
4952 [[nodiscard]] helios::ObjectType getObjectType(uint ObjID) const;
4953
4955
4958 [[nodiscard]] Tile *getTileObjectPointer(uint ObjID) const;
4959
4961
4964 [[nodiscard]] float getTileObjectAreaRatio(uint ObjID) const;
4965
4967
4970 [[nodiscard]] std::vector<float> getTileObjectAreaRatio(const std::vector<uint> &ObjIDs) const;
4971
4973
4977 void setTileObjectSubdivisionCount(const std::vector<uint> &ObjIDs, const int2 &new_subdiv);
4978
4980
4984 void setTileObjectSubdivisionCount(const std::vector<uint> &ObjIDs, float area_ratio);
4985
4987
4992 [[nodiscard]] helios::vec3 getTileObjectCenter(uint ObjID) const;
4993
4995
4998 [[nodiscard]] helios::vec2 getTileObjectSize(uint ObjID) const;
4999
5001
5004 [[nodiscard]] helios::int2 getTileObjectSubdivisionCount(uint ObjID) const;
5005
5007
5010 [[nodiscard]] helios::vec3 getTileObjectNormal(uint ObjID) const;
5011
5013
5016 [[nodiscard]] std::vector<helios::vec2> getTileObjectTextureUV(uint ObjID) const;
5017
5019
5022 [[nodiscard]] std::vector<helios::vec3> getTileObjectVertices(uint ObjID) const;
5023
5025
5028 [[nodiscard]] Sphere *getSphereObjectPointer(uint ObjID) const;
5029
5031
5034 [[nodiscard]] helios::vec3 getSphereObjectCenter(uint ObjID) const;
5035
5037
5040 [[nodiscard]] helios::vec3 getSphereObjectRadius(uint ObjID) const;
5041
5043
5046 [[nodiscard]] uint getSphereObjectSubdivisionCount(uint ObjID) const;
5047
5049
5052 [[nodiscard]] float getSphereObjectVolume(uint ObjID) const;
5053
5055
5058 [[nodiscard]] Tube *getTubeObjectPointer(uint ObjID) const;
5059
5061
5064 [[nodiscard]] uint getTubeObjectSubdivisionCount(uint ObjID) const;
5065
5067
5070 [[nodiscard]] std::vector<helios::vec3> getTubeObjectNodes(uint ObjID) const;
5071
5073
5076 [[nodiscard]] uint getTubeObjectNodeCount(uint ObjID) const;
5077
5079
5082 [[nodiscard]] std::vector<float> getTubeObjectNodeRadii(uint ObjID) const;
5083
5085
5088 [[nodiscard]] std::vector<RGBcolor> getTubeObjectNodeColors(uint ObjID) const;
5089
5091
5094 [[nodiscard]] float getTubeObjectVolume(uint ObjID) const;
5095
5097
5101 [[nodiscard]] float getTubeObjectSegmentVolume(uint ObjID, uint segment_index) const;
5102
5104
5110 void appendTubeSegment(uint ObjID, const helios::vec3 &node_position, float radius, const RGBcolor &color);
5111
5113
5120 void appendTubeSegment(uint ObjID, const helios::vec3 &node_position, float node_radius, const char *texturefile, const helios::vec2 &textureuv_ufrac);
5121
5123
5127 void scaleTubeGirth(uint ObjID, float scale_factor);
5128
5130
5134 void setTubeRadii(uint ObjID, const std::vector<float> &node_radii);
5135
5137
5141 void scaleTubeLength(uint ObjID, float scale_factor);
5142
5144
5148 void pruneTubeNodes(uint ObjID, uint node_index);
5149
5151
5155 void setTubeNodes(uint ObjID, const std::vector<helios::vec3> &node_xyz);
5156
5158
5161 [[nodiscard]] Box *getBoxObjectPointer(uint ObjID) const;
5162
5164
5167 [[nodiscard]] helios::vec3 getBoxObjectCenter(uint ObjID) const;
5168
5170
5173 [[nodiscard]] helios::vec3 getBoxObjectSize(uint ObjID) const;
5174
5176
5179 [[nodiscard]] helios::int3 getBoxObjectSubdivisionCount(uint ObjID) const;
5180
5182
5185 [[nodiscard]] float getBoxObjectVolume(uint ObjID) const;
5186
5188
5191 [[nodiscard]] Disk *getDiskObjectPointer(uint ObjID) const;
5192
5194
5197 [[nodiscard]] helios::vec3 getDiskObjectCenter(uint ObjID) const;
5198
5200
5203 [[nodiscard]] helios::vec2 getDiskObjectSize(uint ObjID) const;
5204
5206
5209 [[nodiscard]] uint getDiskObjectSubdivisionCount(uint ObjID) const;
5210
5212
5215 [[nodiscard]] Polymesh *getPolymeshObjectPointer(uint ObjID) const;
5216
5218
5221 [[nodiscard]] float getPolymeshObjectVolume(uint ObjID) const;
5222
5224
5227 [[nodiscard]] Cone *getConeObjectPointer(uint ObjID) const;
5228
5230
5233 [[nodiscard]] uint getConeObjectSubdivisionCount(uint ObjID) const;
5234
5236
5239 [[nodiscard]] std::vector<helios::vec3> getConeObjectNodes(uint ObjID) const;
5240
5242
5245 [[nodiscard]] std::vector<float> getConeObjectNodeRadii(uint ObjID) const;
5246
5248
5252 [[nodiscard]] helios::vec3 getConeObjectNode(uint ObjID, int number) const;
5253
5255
5259 [[nodiscard]] float getConeObjectNodeRadius(uint ObjID, int number) const;
5260
5262
5265 [[nodiscard]] helios::vec3 getConeObjectAxisUnitVector(uint ObjID) const;
5266
5268
5272 [[nodiscard]] float getConeObjectLength(uint ObjID) const;
5273
5275
5278 [[nodiscard]] float getConeObjectVolume(uint ObjID) const;
5279
5281
5290 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv);
5291
5293
5302 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const RGBcolor &color);
5303
5305
5314 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile);
5315
5317
5327 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile, const int2 &texture_repeat);
5328
5330
5338 uint addSphereObject(uint Ndivs, const vec3 &center, float radius);
5339
5341
5349 uint addSphereObject(uint Ndivs, const vec3 &center, float radius, const RGBcolor &color);
5350
5352
5360 uint addSphereObject(uint Ndivs, const vec3 &center, float radius, const char *texturefile);
5361
5363
5371 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius);
5372
5374
5382 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius, const RGBcolor &color);
5383
5385
5393 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius, const char *texturefile);
5394
5396
5405 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius);
5406
5408
5417 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const std::vector<RGBcolor> &color);
5418
5420
5430 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile);
5431
5433
5444 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile, const std::vector<float> &textureuv_ufrac);
5445
5447
5456 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv);
5457
5459
5468 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color);
5469
5471
5480 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile);
5481
5483
5493 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color, bool reverse_normals);
5494
5496
5506 uint addBoxObject(vec3 center, const vec3 &size, const int3 &subdiv, const char *texturefile, bool reverse_normals);
5507
5509
5518 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size);
5519
5521
5530 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
5531
5533
5542 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
5543
5545
5554 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
5555
5557
5567 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
5568
5570
5579 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
5580
5582
5591 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
5592
5594
5604 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texturefile);
5605
5607
5612 uint addPolymeshObject(const std::vector<uint> &UUIDs);
5613
5615
5626 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1);
5627
5629
5640 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const RGBcolor &color);
5641
5643
5654 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const char *texturefile);
5655
5657
5665 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius);
5666
5668
5676 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius, const RGBcolor &color);
5677
5679
5687 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius, const char *texturefile);
5688
5690
5699 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv);
5700
5702
5711 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const RGBcolor &color);
5712
5714
5723 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile);
5724
5726
5736 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile, const int2 &texture_repeat);
5737
5739
5748 std::vector<uint> addTube(uint Ndivs, const std::vector<vec3> &nodes, const std::vector<float> &radius);
5749
5751
5760 std::vector<uint> addTube(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const std::vector<RGBcolor> &color);
5761
5763
5772 std::vector<uint> addTube(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile);
5773
5775
5784 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv);
5785
5787
5796 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color);
5797
5799
5808 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile);
5809
5811
5821 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color, bool reverse_normals);
5822
5824
5834 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile, bool reverse_normals);
5835
5837
5846 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size);
5847
5849
5858 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
5859
5861
5870 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
5871
5873
5882 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
5883
5885
5895 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
5896
5898
5907 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
5908
5910
5919 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
5920
5922
5932 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texturefile);
5933
5935
5945 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1);
5946
5948
5958 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, RGBcolor &color);
5959
5961
5971 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const char *texturefile);
5972
5974
5981 void addTimeseriesData(const char *label, float value, const Date &date, const Time &time);
5982
5984
5989 void setCurrentTimeseriesPoint(const char *label, uint index);
5990
5992
5999 float queryTimeseriesData(const char *label, const Date &date, const Time &time) const;
6000
6002
6007 float queryTimeseriesData(const char *label) const;
6008
6010
6016 float queryTimeseriesData(const char *label, uint index) const;
6017
6019
6025 Time queryTimeseriesTime(const char *label, uint index) const;
6026
6028
6034 Date queryTimeseriesDate(const char *label, uint index) const;
6035
6037
6041 uint getTimeseriesLength(const char *label) const;
6042
6044
6048 bool doesTimeseriesVariableExist(const char *label) const;
6049
6051 [[nodiscard]] std::vector<std::string> listTimeseriesVariables() const;
6052
6054
6061 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);
6062
6064
6069 void getDomainBoundingBox(helios::vec2 &xbounds, helios::vec2 &ybounds, helios::vec2 &zbounds) const;
6070
6072
6078 void getDomainBoundingBox(const std::vector<uint> &UUIDs, helios::vec2 &xbounds, helios::vec2 &ybounds, helios::vec2 &zbounds) const;
6079
6081
6085 void getDomainBoundingSphere(helios::vec3 &center, float &radius) const;
6086
6088
6093 void getDomainBoundingSphere(const std::vector<uint> &UUIDs, helios::vec3 &center, float &radius) const;
6094
6096
6099 void cropDomainX(const vec2 &xbounds);
6100
6102
6105 void cropDomainY(const vec2 &ybounds);
6106
6108
6111 void cropDomainZ(const vec2 &zbounds);
6112
6114
6120 void cropDomain(std::vector<uint> &UUIDs, const vec2 &xbounds, const vec2 &ybounds, const vec2 &zbounds);
6121
6123
6128 void cropDomain(const vec2 &xbounds, const vec2 &ybounds, const vec2 &zbounds);
6129
6131
6137 void colorPrimitiveByDataPseudocolor(const std::vector<uint> &UUIDs, const std::string &primitive_data, const std::string &colormap, uint Ncolors);
6138
6140
6148 void colorPrimitiveByDataPseudocolor(const std::vector<uint> &UUIDs, const std::string &primitive_data, const std::string &colormap, uint Ncolors, float data_min, float data_max);
6149
6151
6157 std::vector<uint> loadXML(const char *filename, bool quiet = false);
6158
6160
6163 [[nodiscard]] std::vector<std::string> getLoadedXMLFiles();
6164
6166
6172 static bool scanXMLForTag(const std::string &filename, const std::string &tag, const std::string &label = "");
6173
6175
6179 void writeXML(const char *filename, bool quiet = false) const;
6180
6182
6187 void writeXML(const char *filename, const std::vector<uint> &UUIDs, bool quiet = false) const;
6188
6190
6195 void writeXML_byobject(const char *filename, const std::vector<uint> &UUIDs, bool quiet = false) const;
6196
6198
6203 void writePrimitiveData(const std::string &filename, const std::vector<std::string> &column_format, bool print_header = false) const;
6204
6206
6212 void writePrimitiveData(const std::string &filename, const std::vector<std::string> &column_format, const std::vector<uint> &UUIDs, bool print_header = false) const;
6213
6215
6221 std::vector<uint> loadPLY(const char *filename, bool silent = false);
6222
6224
6233 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const std::string &upaxis = "YUP", bool silent = false);
6234
6236
6246 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const std::string &upaxis = "YUP", bool silent = false);
6247
6249
6258 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const RGBcolor &default_color, const std::string &upaxis = "YUP", bool silent = false);
6259
6261
6271 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);
6272
6274
6277 void writePLY(const char *filename) const;
6278
6280
6284 void writePLY(const char *filename, const std::vector<uint> &UUIDs) const;
6285
6286 // Asset directory registration removed - now using HELIOS_BUILD resolution
6287
6289
6293 std::vector<uint> loadOBJ(const char *filename, bool silent = false);
6294
6296
6305 std::vector<uint> loadOBJ(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const RGBcolor &default_color, bool silent = false);
6306
6308
6318 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);
6319
6320
6322
6332 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);
6333
6335
6340 void writeOBJ(const std::string &filename, bool write_normals = false, bool silent = false) const;
6341
6343
6349 void writeOBJ(const std::string &filename, const std::vector<uint> &UUIDs, bool write_normals = false, bool silent = false) const;
6350
6352
6359 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;
6360
6361 //------------ FILE PATH RESOLUTION ----------------//
6362
6364
6369 std::filesystem::path resolveFilePath(const std::string &filename) const;
6370
6372
6378 void setDate(int day, int month, int year);
6379
6381
6385 void setDate(const Date &date);
6386
6388
6393 void setDate(int Julian_day, int year);
6394
6396
6400 [[nodiscard]] helios::Date getDate() const;
6401
6403
6407 [[nodiscard]] const char *getMonthString() const;
6408
6410
6414 [[nodiscard]] int getJulianDate() const;
6415
6417
6423 void setTime(int minute, int hour);
6424
6426
6433 void setTime(int second, int minute, int hour);
6434
6436
6441 void setTime(const Time &time);
6442
6444
6448 [[nodiscard]] helios::Time getTime() const;
6449
6451
6454 void setLocation(const helios::Location &location);
6455
6457
6460 [[nodiscard]] helios::Location getLocation() const;
6461
6463
6466 float randu();
6467
6469
6474 float randu(float min, float max);
6475
6477
6482 int randu(int min, int max);
6483
6485
6488 float randn();
6489
6491
6496 float randn(float mean, float stddev);
6497
6499
6503 void duplicatePrimitiveData(const char *existing_data_label, const char *copy_data_label);
6504
6506
6511 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, float &mean) const;
6512
6514
6519 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, double &mean) const;
6520
6522
6527 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &mean) const;
6528
6530
6535 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &mean) const;
6536
6538
6543 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &mean) const;
6544
6546
6551 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, float &awt_mean) const;
6552
6554
6559 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, double &awt_mean) const;
6560
6562
6567 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &awt_mean) const;
6568
6570
6575 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &awt_mean) const;
6576
6578
6583 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &awt_mean) const;
6584
6586
6591 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, float &sum) const;
6592
6594
6599 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, double &sum) const;
6600
6602
6607 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &sum) const;
6608
6610
6615 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &sum) const;
6616
6618
6623 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &sum) const;
6624
6626
6631 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, float &awt_sum) const;
6632
6634
6639 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, double &sum) const;
6640
6642
6647 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &sum) const;
6648
6650
6655 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &sum) const;
6656
6658
6663 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &sum) const;
6664
6666
6672 void scalePrimitiveData(const std::vector<uint> &UUIDs, const std::string &label, float scaling_factor);
6673
6675
6680 void scalePrimitiveData(const std::string &label, float scaling_factor);
6681
6683
6689 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, int increment);
6690
6692
6698 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, uint increment);
6699
6701
6707 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, float increment);
6708
6710
6716 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, double increment);
6717
6719
6725 void aggregatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label);
6726
6728
6734 void aggregatePrimitiveDataProduct(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label);
6735
6737
6741 [[nodiscard]] float sumPrimitiveSurfaceArea(const std::vector<uint> &UUIDs) const;
6742
6744
6752 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, float filter_value, const std::string &comparator) const;
6753
6755
6763 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, double filter_value, const std::string &comparator) const;
6764
6766
6774 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, int filter_value, const std::string &comparator) const;
6775
6777
6785 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, uint filter_value, const std::string &comparator) const;
6786
6788
6795 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, const std::string &filter_value) const;
6796
6798
6806 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, float filter_value, const std::string &comparator) const;
6807
6809
6817 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, double filter_value, const std::string &comparator) const;
6818
6820
6828 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, int filter_value, const std::string &comparator) const;
6829
6831
6839 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, uint filter_value, const std::string &comparator) const;
6840
6842
6849 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, const std::string &filter_value) const;
6850
6852
6862 std::vector<std::string> generateTexturesFromColormap(const std::string &texturefile, const std::vector<RGBcolor> &colormap_data);
6863
6865
6870 std::vector<RGBcolor> generateColormap(const std::string &colormap, uint Ncolors);
6871
6873
6880 std::vector<RGBcolor> generateColormap(const std::vector<helios::RGBcolor> &ctable, const std::vector<float> &cfrac, uint Ncolors);
6881
6882 // ---------- Template method implementations for data type consistency ---------- //
6883
6884 template<typename T>
6885 void storeDataWithTypeCasting(uint UUID, const char *label, const T &data, HeliosDataType target_type) {
6886 // Only cast between numeric scalar types
6887 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>) {
6888 if (target_type == HELIOS_TYPE_INT) {
6889 primitives.at(UUID)->setPrimitiveData(label, static_cast<int>(data));
6890 } else if (target_type == HELIOS_TYPE_UINT) {
6891 primitives.at(UUID)->setPrimitiveData(label, static_cast<uint>(data));
6892 } else if (target_type == HELIOS_TYPE_FLOAT) {
6893 primitives.at(UUID)->setPrimitiveData(label, static_cast<float>(data));
6894 } else if (target_type == HELIOS_TYPE_DOUBLE) {
6895 primitives.at(UUID)->setPrimitiveData(label, static_cast<double>(data));
6896 } else {
6897 // Fallback: store as original type
6898 primitives.at(UUID)->setPrimitiveData(label, data);
6899 }
6900 } else {
6901 // For non-numeric types, store as-is
6902 primitives.at(UUID)->setPrimitiveData(label, data);
6903 }
6904 }
6905
6906 template<typename T>
6907 void storeObjectDataWithTypeCasting(uint objID, const char *label, const T &data, HeliosDataType target_type) {
6908 // Only cast between numeric scalar types
6909 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>) {
6910 if (target_type == HELIOS_TYPE_INT) {
6911 objects.at(objID)->setObjectData(label, static_cast<int>(data));
6912 } else if (target_type == HELIOS_TYPE_UINT) {
6913 objects.at(objID)->setObjectData(label, static_cast<uint>(data));
6914 } else if (target_type == HELIOS_TYPE_FLOAT) {
6915 objects.at(objID)->setObjectData(label, static_cast<float>(data));
6916 } else if (target_type == HELIOS_TYPE_DOUBLE) {
6917 objects.at(objID)->setObjectData(label, static_cast<double>(data));
6918 } else {
6919 // Fallback: store as original type
6920 objects.at(objID)->setObjectData(label, data);
6921 }
6922 } else {
6923 // For non-numeric types, store as-is
6924 objects.at(objID)->setObjectData(label, data);
6925 }
6926 }
6927
6928 template<typename T>
6929 HeliosDataType registerOrValidatePrimitiveDataType(const std::string &label, HeliosDataType data_type) {
6930 auto it = primitive_data_type_registry.find(label);
6931 if (it == primitive_data_type_registry.end()) {
6932 // First time this label is used - register the type
6933 primitive_data_type_registry[label] = data_type;
6934 return data_type;
6935 } else {
6936 // Label exists - check for type consistency
6937 HeliosDataType expected_type = it->second;
6938 if (expected_type != data_type) {
6939 // Types don't match - check if casting is possible
6940 if (!isTypeCastingSupported(data_type, expected_type)) {
6941 helios_runtime_error("ERROR (Context::registerOrValidatePrimitiveDataType): Data type mismatch for label '" + label + "'. Expected " + dataTypeToString(expected_type) + " but got " + dataTypeToString(data_type) +
6942 ". Type casting between these types is not supported.");
6943 } else {
6944 std::cerr << "WARNING (Context::registerOrValidatePrimitiveDataType): Type casting from " + dataTypeToString(data_type) + " to " + dataTypeToString(expected_type) + " for label '" + label +
6945 "'. Consider using consistent types."
6946 << std::endl;
6947 }
6948 }
6949 return expected_type;
6950 }
6951 }
6952
6953 template<typename T>
6954 HeliosDataType registerOrValidateObjectDataType(const std::string &label, HeliosDataType data_type) {
6955 auto it = object_data_type_registry.find(label);
6956 if (it == object_data_type_registry.end()) {
6957 // First time this label is used - register the type
6958 object_data_type_registry[label] = data_type;
6959 return data_type;
6960 } else {
6961 // Label exists - check for type consistency
6962 HeliosDataType expected_type = it->second;
6963 if (expected_type != data_type) {
6964 // Types don't match - check if casting is possible
6965 if (!isTypeCastingSupported(data_type, expected_type)) {
6966 helios_runtime_error("ERROR (Context::registerOrValidateObjectDataType): Data type mismatch for label '" + label + "'. Expected " + dataTypeToString(expected_type) + " but got " + dataTypeToString(data_type) +
6967 ". Type casting between these types is not supported.");
6968 } else {
6969 std::cerr << "WARNING (Context::registerOrValidateObjectDataType): Type casting from " + dataTypeToString(data_type) + " to " + dataTypeToString(expected_type) + " for label '" + label + "'. Consider using consistent types."
6970 << std::endl;
6971 }
6972 }
6973 return expected_type;
6974 }
6975 }
6976
6977 //----------- TEMPLATE METHOD IMPLEMENTATIONS FOR VALUE REGISTRY ----------//
6978
6980 template<typename T>
6981 void incrementPrimitiveValueRegistry(const std::string &label, const T &value) {
6982 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 *>) {
6983 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
6984 primitive_string_value_registry[label][string_value]++;
6985 } else if constexpr (std::is_same_v<T, int>) {
6986 primitive_int_value_registry[label][value]++;
6987 } else if constexpr (std::is_same_v<T, uint>) {
6988 primitive_uint_value_registry[label][value]++;
6989 }
6990 }
6991
6993 template<typename T>
6994 void decrementPrimitiveValueRegistry(const std::string &label, const T &value) {
6995 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 *>) {
6996 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
6997 auto label_it = primitive_string_value_registry.find(label);
6998 if (label_it != primitive_string_value_registry.end()) {
6999 auto value_it = label_it->second.find(string_value);
7000 if (value_it != label_it->second.end() && value_it->second > 0) {
7001 value_it->second--;
7002 if (value_it->second == 0) {
7003 label_it->second.erase(value_it);
7004 if (label_it->second.empty()) {
7005 primitive_string_value_registry.erase(label_it);
7006 }
7007 }
7008 }
7009 }
7010 } else if constexpr (std::is_same_v<T, int>) {
7011 auto label_it = primitive_int_value_registry.find(label);
7012 if (label_it != primitive_int_value_registry.end()) {
7013 auto value_it = label_it->second.find(value);
7014 if (value_it != label_it->second.end() && value_it->second > 0) {
7015 value_it->second--;
7016 if (value_it->second == 0) {
7017 label_it->second.erase(value_it);
7018 if (label_it->second.empty()) {
7019 primitive_int_value_registry.erase(label_it);
7020 }
7021 }
7022 }
7023 }
7024 } else if constexpr (std::is_same_v<T, uint>) {
7025 auto label_it = primitive_uint_value_registry.find(label);
7026 if (label_it != primitive_uint_value_registry.end()) {
7027 auto value_it = label_it->second.find(value);
7028 if (value_it != label_it->second.end() && value_it->second > 0) {
7029 value_it->second--;
7030 if (value_it->second == 0) {
7031 label_it->second.erase(value_it);
7032 if (label_it->second.empty()) {
7033 primitive_uint_value_registry.erase(label_it);
7034 }
7035 }
7036 }
7037 }
7038 }
7039 }
7040
7042 template<typename T>
7043 void incrementObjectValueRegistry(const std::string &label, const T &value) {
7044 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 *>) {
7045 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7046 object_string_value_registry[label][string_value]++;
7047 } else if constexpr (std::is_same_v<T, int>) {
7048 object_int_value_registry[label][value]++;
7049 } else if constexpr (std::is_same_v<T, uint>) {
7050 object_uint_value_registry[label][value]++;
7051 }
7052 }
7053
7055 template<typename T>
7056 void decrementObjectValueRegistry(const std::string &label, const T &value) {
7057 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 *>) {
7058 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7059 auto label_it = object_string_value_registry.find(label);
7060 if (label_it != object_string_value_registry.end()) {
7061 auto value_it = label_it->second.find(string_value);
7062 if (value_it != label_it->second.end() && value_it->second > 0) {
7063 value_it->second--;
7064 if (value_it->second == 0) {
7065 label_it->second.erase(value_it);
7066 if (label_it->second.empty()) {
7067 object_string_value_registry.erase(label_it);
7068 }
7069 }
7070 }
7071 }
7072 } else if constexpr (std::is_same_v<T, int>) {
7073 auto label_it = object_int_value_registry.find(label);
7074 if (label_it != object_int_value_registry.end()) {
7075 auto value_it = label_it->second.find(value);
7076 if (value_it != label_it->second.end() && value_it->second > 0) {
7077 value_it->second--;
7078 if (value_it->second == 0) {
7079 label_it->second.erase(value_it);
7080 if (label_it->second.empty()) {
7081 object_int_value_registry.erase(label_it);
7082 }
7083 }
7084 }
7085 }
7086 } else if constexpr (std::is_same_v<T, uint>) {
7087 auto label_it = object_uint_value_registry.find(label);
7088 if (label_it != object_uint_value_registry.end()) {
7089 auto value_it = label_it->second.find(value);
7090 if (value_it != label_it->second.end() && value_it->second > 0) {
7091 value_it->second--;
7092 if (value_it->second == 0) {
7093 label_it->second.erase(value_it);
7094 if (label_it->second.empty()) {
7095 object_uint_value_registry.erase(label_it);
7096 }
7097 }
7098 }
7099 }
7100 }
7101 }
7102
7103 //----------- UNIQUE VALUE QUERY METHODS ----------//
7104
7106
7112 template<typename T>
7113 void getUniquePrimitiveDataValues(const std::string &label, std::vector<T> &values) const {
7114 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.");
7115
7117 helios_runtime_error("ERROR (Context::getUniquePrimitiveDataValues): Value-level caching is not enabled for primitive data label '" + label + "'. Use enablePrimitiveDataValueCaching() first.");
7118 }
7119
7120 values.clear();
7121
7122 if constexpr (std::is_same_v<T, std::string>) {
7123 auto it = primitive_string_value_registry.find(label);
7124 if (it != primitive_string_value_registry.end()) {
7125 values.reserve(it->second.size());
7126 for (const auto &[value, count]: it->second) {
7127 if (count > 0) {
7128 values.push_back(value);
7129 }
7130 }
7131 }
7132 } else if constexpr (std::is_same_v<T, int>) {
7133 auto it = primitive_int_value_registry.find(label);
7134 if (it != primitive_int_value_registry.end()) {
7135 values.reserve(it->second.size());
7136 for (const auto &[value, count]: it->second) {
7137 if (count > 0) {
7138 values.push_back(value);
7139 }
7140 }
7141 }
7142 } else if constexpr (std::is_same_v<T, uint>) {
7143 auto it = primitive_uint_value_registry.find(label);
7144 if (it != primitive_uint_value_registry.end()) {
7145 values.reserve(it->second.size());
7146 for (const auto &[value, count]: it->second) {
7147 if (count > 0) {
7148 values.push_back(value);
7149 }
7150 }
7151 }
7152 }
7153 }
7154
7156
7162 template<typename T>
7163 void getUniqueObjectDataValues(const std::string &label, std::vector<T> &values) const {
7164 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.");
7165
7166 if (!isObjectDataValueCachingEnabled(label)) {
7167 helios_runtime_error("ERROR (Context::getUniqueObjectDataValues): Value-level caching is not enabled for object data label '" + label + "'. Use enableObjectDataValueCaching() first.");
7168 }
7169
7170 values.clear();
7171
7172 if constexpr (std::is_same_v<T, std::string>) {
7173 auto it = object_string_value_registry.find(label);
7174 if (it != object_string_value_registry.end()) {
7175 values.reserve(it->second.size());
7176 for (const auto &[value, count]: it->second) {
7177 if (count > 0) {
7178 values.push_back(value);
7179 }
7180 }
7181 }
7182 } else if constexpr (std::is_same_v<T, int>) {
7183 auto it = object_int_value_registry.find(label);
7184 if (it != object_int_value_registry.end()) {
7185 values.reserve(it->second.size());
7186 for (const auto &[value, count]: it->second) {
7187 if (count > 0) {
7188 values.push_back(value);
7189 }
7190 }
7191 }
7192 } else if constexpr (std::is_same_v<T, uint>) {
7193 auto it = object_uint_value_registry.find(label);
7194 if (it != object_uint_value_registry.end()) {
7195 values.reserve(it->second.size());
7196 for (const auto &[value, count]: it->second) {
7197 if (count > 0) {
7198 values.push_back(value);
7199 }
7200 }
7201 }
7202 }
7203 }
7204 };
7205
7206} // namespace helios
7207
7208
7209#endif