1.3.64
 
Loading...
Searching...
No Matches
Context.h
Go to the documentation of this file.
1
16#ifndef HELIOS_CONTEXT
17#define HELIOS_CONTEXT
18
19#include <set>
20#include <unordered_set>
21#include <utility>
22
23#include "global.h"
24
26
28namespace helios {
29
30 class Context; // forward declaration of Context class
31
41
71
73 class Texture {
74 public:
76 Texture() = default;
77
79
82 explicit Texture(const char *texture_file);
83
85 [[nodiscard]] std::string getTextureFile() const;
86
88 [[nodiscard]] int2 getImageResolution() const;
89
91 [[nodiscard]] bool hasTransparencyChannel() const;
92
94 [[nodiscard]] const std::vector<std::vector<bool>> *getTransparencyData() const;
95
97
101 [[nodiscard]] float getSolidFraction(const std::vector<vec2> &uvs);
102
103 private:
104 std::string filename;
105 bool hastransparencychannel{};
106 std::vector<std::vector<bool>> transparencydata;
107 int2 image_resolution;
108 float solidfraction{};
109 std::unordered_map<PixelUVKey, float, PixelUVKeyHash> solidFracCache;
110
117 [[nodiscard]] float computeSolidFraction(const std::vector<vec2> &uvs) const;
118 };
119
121
129 struct Material {
132
134 std::string label;
135
138
140 std::string texture_file;
141
143
145
147
150
152
154
156 std::map<std::string, HeliosDataType> material_data_types;
158 std::map<std::string, std::vector<int>> material_data_int;
160 std::map<std::string, std::vector<uint>> material_data_uint;
162 std::map<std::string, std::vector<float>> material_data_float;
164 std::map<std::string, std::vector<double>> material_data_double;
166 std::map<std::string, std::vector<vec2>> material_data_vec2;
168 std::map<std::string, std::vector<vec3>> material_data_vec3;
170 std::map<std::string, std::vector<vec4>> material_data_vec4;
172 std::map<std::string, std::vector<int2>> material_data_int2;
174 std::map<std::string, std::vector<int3>> material_data_int3;
176 std::map<std::string, std::vector<int4>> material_data_int4;
178 std::map<std::string, std::vector<std::string>> material_data_string;
180 std::map<std::string, std::vector<bool>> material_data_bool;
181
185
187 Material(uint ID, const std::string &lbl, const RGBAcolor &c, const std::string &tex, bool override, uint twosided = 1) :
188 materialID(ID), label(lbl), color(c), texture_file(tex), texture_color_overridden(override), twosided_flag(twosided), reference_count(0) {
189 }
190
191 //-------- Material Data Methods ---------- //
192
194
199 template<typename T>
200 void setMaterialData(const char *label, const T &data) {
201 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
202 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
203 "Material::setMaterialData() was called with an unsupported type.");
204
205 if constexpr (std::is_same_v<T, int>) {
206 material_data_int[label] = {data};
208 } else if constexpr (std::is_same_v<T, uint>) {
209 material_data_uint[label] = {data};
211 } else if constexpr (std::is_same_v<T, float>) {
212 material_data_float[label] = {data};
214 } else if constexpr (std::is_same_v<T, double>) {
215 material_data_double[label] = {data};
217 } else if constexpr (std::is_same_v<T, vec2>) {
218 material_data_vec2[label] = {data};
220 } else if constexpr (std::is_same_v<T, vec3>) {
221 material_data_vec3[label] = {data};
223 } else if constexpr (std::is_same_v<T, vec4>) {
224 material_data_vec4[label] = {data};
226 } else if constexpr (std::is_same_v<T, int2>) {
227 material_data_int2[label] = {data};
229 } else if constexpr (std::is_same_v<T, int3>) {
230 material_data_int3[label] = {data};
232 } else if constexpr (std::is_same_v<T, int4>) {
233 material_data_int4[label] = {data};
235 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
236 material_data_string[label] = {data};
238 }
239 }
240
242
247 template<typename T>
248 void setMaterialData(const char *label, const std::vector<T> &data) {
249 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
250 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
251 "Material::setMaterialData() was called with an unsupported type.");
252
253 if constexpr (std::is_same_v<T, int>) {
254 material_data_int[label] = data;
256 } else if constexpr (std::is_same_v<T, uint>) {
259 } else if constexpr (std::is_same_v<T, float>) {
262 } else if constexpr (std::is_same_v<T, double>) {
265 } else if constexpr (std::is_same_v<T, vec2>) {
268 } else if constexpr (std::is_same_v<T, vec3>) {
271 } else if constexpr (std::is_same_v<T, vec4>) {
274 } else if constexpr (std::is_same_v<T, int2>) {
277 } else if constexpr (std::is_same_v<T, int3>) {
280 } else if constexpr (std::is_same_v<T, int4>) {
283 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
286 }
287 }
288
290
295 template<typename T>
296 void getMaterialData(const char *label, T &data) const {
298 helios_runtime_error("ERROR (Material::getMaterialData): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
299 }
300 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
301 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
302 "Material::getMaterialData() was called with an unsupported type.");
303
305
306 if constexpr (std::is_same_v<T, int>) {
307 if (type == HELIOS_TYPE_INT) {
308 data = material_data_int.at(label).front();
309 } else {
310 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int.");
311 }
312 } else if constexpr (std::is_same_v<T, uint>) {
313 if (type == HELIOS_TYPE_UINT) {
314 data = material_data_uint.at(label).front();
315 } else {
316 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type uint, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type uint.");
317 }
318 } else if constexpr (std::is_same_v<T, float>) {
319 if (type == HELIOS_TYPE_FLOAT) {
320 data = material_data_float.at(label).front();
321 } else {
322 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type float, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type float.");
323 }
324 } else if constexpr (std::is_same_v<T, double>) {
325 if (type == HELIOS_TYPE_DOUBLE) {
326 data = material_data_double.at(label).front();
327 } else {
328 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type double, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type double.");
329 }
330 } else if constexpr (std::is_same_v<T, vec2>) {
331 if (type == HELIOS_TYPE_VEC2) {
332 data = material_data_vec2.at(label).front();
333 } else {
334 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec2.");
335 }
336 } else if constexpr (std::is_same_v<T, vec3>) {
337 if (type == HELIOS_TYPE_VEC3) {
338 data = material_data_vec3.at(label).front();
339 } else {
340 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec3.");
341 }
342 } else if constexpr (std::is_same_v<T, vec4>) {
343 if (type == HELIOS_TYPE_VEC4) {
344 data = material_data_vec4.at(label).front();
345 } else {
346 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec4.");
347 }
348 } else if constexpr (std::is_same_v<T, int2>) {
349 if (type == HELIOS_TYPE_INT2) {
350 data = material_data_int2.at(label).front();
351 } else {
352 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int2.");
353 }
354 } else if constexpr (std::is_same_v<T, int3>) {
355 if (type == HELIOS_TYPE_INT3) {
356 data = material_data_int3.at(label).front();
357 } else {
358 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int3.");
359 }
360 } else if constexpr (std::is_same_v<T, int4>) {
361 if (type == HELIOS_TYPE_INT4) {
362 data = material_data_int4.at(label).front();
363 } else {
364 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int4.");
365 }
366 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
367 if (type == HELIOS_TYPE_STRING) {
368 data = material_data_string.at(label).front();
369 } else {
370 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type string, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type string.");
371 }
372 }
373 }
374
376
381 template<typename T>
382 void getMaterialData(const char *label, std::vector<T> &data) const {
384 helios_runtime_error("ERROR (Material::getMaterialData): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
385 }
386 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
387 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
388 "Material::getMaterialData() was called with an unsupported type.");
389
391
392 if constexpr (std::is_same_v<T, int>) {
393 if (type == HELIOS_TYPE_INT) {
394 data = material_data_int.at(label);
395 } else {
396 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int.");
397 }
398 } else if constexpr (std::is_same_v<T, uint>) {
399 if (type == HELIOS_TYPE_UINT) {
400 data = material_data_uint.at(label);
401 } else {
402 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type uint, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type uint.");
403 }
404 } else if constexpr (std::is_same_v<T, float>) {
405 if (type == HELIOS_TYPE_FLOAT) {
406 data = material_data_float.at(label);
407 } else {
408 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type float, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type float.");
409 }
410 } else if constexpr (std::is_same_v<T, double>) {
411 if (type == HELIOS_TYPE_DOUBLE) {
412 data = material_data_double.at(label);
413 } else {
414 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type double, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type double.");
415 }
416 } else if constexpr (std::is_same_v<T, vec2>) {
417 if (type == HELIOS_TYPE_VEC2) {
418 data = material_data_vec2.at(label);
419 } else {
420 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec2.");
421 }
422 } else if constexpr (std::is_same_v<T, vec3>) {
423 if (type == HELIOS_TYPE_VEC3) {
424 data = material_data_vec3.at(label);
425 } else {
426 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec3.");
427 }
428 } else if constexpr (std::is_same_v<T, vec4>) {
429 if (type == HELIOS_TYPE_VEC4) {
430 data = material_data_vec4.at(label);
431 } else {
432 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type vec4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type vec4.");
433 }
434 } else if constexpr (std::is_same_v<T, int2>) {
435 if (type == HELIOS_TYPE_INT2) {
436 data = material_data_int2.at(label);
437 } else {
438 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int2, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int2.");
439 }
440 } else if constexpr (std::is_same_v<T, int3>) {
441 if (type == HELIOS_TYPE_INT3) {
442 data = material_data_int3.at(label);
443 } else {
444 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int3, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int3.");
445 }
446 } else if constexpr (std::is_same_v<T, int4>) {
447 if (type == HELIOS_TYPE_INT4) {
448 data = material_data_int4.at(label);
449 } else {
450 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type int4, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type int4.");
451 }
452 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
453 if (type == HELIOS_TYPE_STRING) {
454 data = material_data_string.at(label);
455 } else {
456 helios_runtime_error("ERROR (Material::getMaterialData): Attempted to get data for type string, but data " + std::string(label) + " for material " + std::to_string(materialID) + " does not have type string.");
457 }
458 }
459 }
460
462
466 bool doesMaterialDataExist(const char *label) const {
467 return material_data_types.find(label) != material_data_types.end();
468 }
469
471
478 helios_runtime_error("ERROR (Material::getMaterialDataType): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
479 }
480 return material_data_types.at(label);
481 }
482
484
488 uint getMaterialDataSize(const char *label) const {
490 helios_runtime_error("ERROR (Material::getMaterialDataSize): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
491 }
493 if (type == HELIOS_TYPE_INT) {
494 return material_data_int.at(label).size();
495 } else if (type == HELIOS_TYPE_UINT) {
496 return material_data_uint.at(label).size();
497 } else if (type == HELIOS_TYPE_FLOAT) {
498 return material_data_float.at(label).size();
499 } else if (type == HELIOS_TYPE_DOUBLE) {
500 return material_data_double.at(label).size();
501 } else if (type == HELIOS_TYPE_VEC2) {
502 return material_data_vec2.at(label).size();
503 } else if (type == HELIOS_TYPE_VEC3) {
504 return material_data_vec3.at(label).size();
505 } else if (type == HELIOS_TYPE_VEC4) {
506 return material_data_vec4.at(label).size();
507 } else if (type == HELIOS_TYPE_INT2) {
508 return material_data_int2.at(label).size();
509 } else if (type == HELIOS_TYPE_INT3) {
510 return material_data_int3.at(label).size();
511 } else if (type == HELIOS_TYPE_INT4) {
512 return material_data_int4.at(label).size();
513 } else if (type == HELIOS_TYPE_STRING) {
514 return material_data_string.at(label).size();
515 }
516 return 0;
517 }
518
520
523 void clearMaterialData(const char *label) {
525 helios_runtime_error("ERROR (Material::clearMaterialData): Material data " + std::string(label) + " does not exist for material " + std::to_string(materialID));
526 }
528 if (type == HELIOS_TYPE_INT) {
530 } else if (type == HELIOS_TYPE_UINT) {
532 } else if (type == HELIOS_TYPE_FLOAT) {
534 } else if (type == HELIOS_TYPE_DOUBLE) {
536 } else if (type == HELIOS_TYPE_VEC2) {
538 } else if (type == HELIOS_TYPE_VEC3) {
540 } else if (type == HELIOS_TYPE_VEC4) {
542 } else if (type == HELIOS_TYPE_INT2) {
544 } else if (type == HELIOS_TYPE_INT3) {
546 } else if (type == HELIOS_TYPE_INT4) {
548 } else if (type == HELIOS_TYPE_STRING) {
550 }
552 }
553
555 std::vector<std::string> listMaterialData() const {
556 std::vector<std::string> data_labels;
557 data_labels.reserve(material_data_types.size());
558 for (const auto &data: material_data_types) {
559 data_labels.push_back(data.first);
560 }
561 return data_labels;
562 }
563 };
564
566 struct GlobalData {
567
569 std::vector<int> global_data_int;
571 std::vector<uint> global_data_uint;
573 std::vector<float> global_data_float;
575 std::vector<double> global_data_double;
577 std::vector<vec2> global_data_vec2;
579 std::vector<vec3> global_data_vec3;
581 std::vector<vec4> global_data_vec4;
583 std::vector<int2> global_data_int2;
585 std::vector<int3> global_data_int3;
587 std::vector<int4> global_data_int4;
589 std::vector<std::string> global_data_string;
591 std::vector<bool> global_data_bool;
592
594 size_t size;
598 uint64_t version = 0;
599 };
600
601 //--------------------- GEOMETRIC PRIMITIVES -----------------------------------//
602
603
604 //---------- COMPOUND OBJECTS ----------------//
605
625
627 public:
629
632 virtual ~CompoundObject() = 0;
633
635 [[nodiscard]] uint getObjectID() const;
636
638 [[nodiscard]] helios::ObjectType getObjectType() const;
639
641 [[nodiscard]] uint getPrimitiveCount() const;
642
644 [[nodiscard]] std::vector<uint> getPrimitiveUUIDs() const;
645
647 [[nodiscard]] bool doesObjectContainPrimitive(uint UUID);
648
650 [[nodiscard]] helios::vec3 getObjectCenter() const;
651
653 [[nodiscard]] float getArea() const;
654
656
659 void setColor(const helios::RGBcolor &color);
660
662
665 void setColor(const helios::RGBAcolor &color);
666
669
672 void useTextureColor();
673
675 [[nodiscard]] bool hasTexture() const;
676
678 [[nodiscard]] std::string getTextureFile() const;
679
681
684 void translate(const helios::vec3 &shift);
685
687
691 void rotate(float rotation_radians, const char *rotation_axis_xyz_string);
692
694
698 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector);
699
701
706 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector);
707
709
712 void scale(const helios::vec3 &scale);
713
715
719
721
725 void scaleAboutPoint(const helios::vec3 &scale, const helios::vec3 &point);
726
728
731 void getTransformationMatrix(float (&T)[16]) const;
732
734
737 void setTransformationMatrix(float (&T)[16]);
738
740
743 void setPrimitiveUUIDs(const std::vector<uint> &UUIDs);
744
746
749 void deleteChildPrimitive(uint UUID);
750
752
755 void deleteChildPrimitive(const std::vector<uint> &UUIDs);
756
758
761 [[nodiscard]] bool arePrimitivesComplete() const;
762
763 //-------- Object Data Methods ---------- //
764
766
771 template<typename T>
772 void setObjectData(const char *label, const T &data) {
773
774 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
775 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
776 "CompoundObject::setObjectData() was called with an unsupported type.");
777
778 if constexpr (std::is_same_v<T, int>) {
779 object_data_int[label] = {data};
780 object_data_types[label] = HELIOS_TYPE_INT;
781 } else if constexpr (std::is_same_v<T, uint>) {
782 object_data_uint[label] = {data};
783 object_data_types[label] = HELIOS_TYPE_UINT;
784 } else if constexpr (std::is_same_v<T, float>) {
785 object_data_float[label] = {data};
786 object_data_types[label] = HELIOS_TYPE_FLOAT;
787 } else if constexpr (std::is_same_v<T, double>) {
788 object_data_double[label] = {data};
789 object_data_types[label] = HELIOS_TYPE_DOUBLE;
790 } else if constexpr (std::is_same_v<T, vec2>) {
791 object_data_vec2[label] = {data};
792 object_data_types[label] = HELIOS_TYPE_VEC2;
793 } else if constexpr (std::is_same_v<T, vec3>) {
794 object_data_vec3[label] = {data};
795 object_data_types[label] = HELIOS_TYPE_VEC3;
796 } else if constexpr (std::is_same_v<T, vec4>) {
797 object_data_vec4[label] = {data};
798 object_data_types[label] = HELIOS_TYPE_VEC4;
799 } else if constexpr (std::is_same_v<T, int2>) {
800 object_data_int2[label] = {data};
801 object_data_types[label] = HELIOS_TYPE_INT2;
802 } else if constexpr (std::is_same_v<T, int3>) {
803 object_data_int3[label] = {data};
804 object_data_types[label] = HELIOS_TYPE_INT3;
805 } else if constexpr (std::is_same_v<T, int4>) {
806 object_data_int4[label] = {data};
807 object_data_types[label] = HELIOS_TYPE_INT4;
808 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
809 object_data_string[label] = {data};
810 object_data_types[label] = HELIOS_TYPE_STRING;
811 }
812 }
813
815
820 template<typename T>
821 void setObjectData(const char *label, const std::vector<T> &data) {
822
823 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
824 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
825 "CompoundObject::setObjectData() was called with an unsupported type.");
826
827 if constexpr (std::is_same_v<T, int>) {
828 object_data_int[label] = data;
829 object_data_types[label] = HELIOS_TYPE_INT;
830 } else if constexpr (std::is_same_v<T, uint>) {
831 object_data_uint[label] = data;
832 object_data_types[label] = HELIOS_TYPE_UINT;
833 } else if constexpr (std::is_same_v<T, float>) {
834 object_data_float[label] = data;
835 object_data_types[label] = HELIOS_TYPE_FLOAT;
836 } else if constexpr (std::is_same_v<T, double>) {
837 object_data_double[label] = data;
838 object_data_types[label] = HELIOS_TYPE_DOUBLE;
839 } else if constexpr (std::is_same_v<T, vec2>) {
840 object_data_vec2[label] = data;
841 object_data_types[label] = HELIOS_TYPE_VEC2;
842 } else if constexpr (std::is_same_v<T, vec3>) {
843 object_data_vec3[label] = data;
844 object_data_types[label] = HELIOS_TYPE_VEC3;
845 } else if constexpr (std::is_same_v<T, vec4>) {
846 object_data_vec4[label] = data;
847 object_data_types[label] = HELIOS_TYPE_VEC4;
848 } else if constexpr (std::is_same_v<T, int2>) {
849 object_data_int2[label] = data;
850 object_data_types[label] = HELIOS_TYPE_INT2;
851 } else if constexpr (std::is_same_v<T, int3>) {
852 object_data_int3[label] = data;
853 object_data_types[label] = HELIOS_TYPE_INT3;
854 } else if constexpr (std::is_same_v<T, int4>) {
855 object_data_int4[label] = data;
856 object_data_types[label] = HELIOS_TYPE_INT4;
857 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
858 object_data_string[label] = data;
859 object_data_types[label] = HELIOS_TYPE_STRING;
860 }
861 }
862
864
868 template<typename T>
869 void getObjectData(const char *label, T &data) const {
870#ifdef HELIOS_DEBUG
871 if (!doesObjectDataExist(label)) {
872 helios_runtime_error("ERROR (CompoundObject::getObjectData): Object data " + std::string(label) + " does not exist for primitive " + std::to_string(OID));
873 }
874#endif
875
876 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
877 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>,
878 "CompoundObject::getObjectData() was called with an unsupported type.");
879
880 HeliosDataType type = object_data_types.at(label);
881
882 if constexpr (std::is_same_v<T, int>) {
883 if (type == HELIOS_TYPE_INT) {
884 data = object_data_int.at(label).front();
885 } else {
886 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int.");
887 }
888 } else if constexpr (std::is_same_v<T, uint>) {
889 if (type == HELIOS_TYPE_UINT) {
890 data = object_data_uint.at(label).front();
891 } else {
892 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type uint, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type uint.");
893 }
894 } else if constexpr (std::is_same_v<T, float>) {
895 if (type == HELIOS_TYPE_FLOAT) {
896 data = object_data_float.at(label).front();
897 } else {
898 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type float, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type float.");
899 }
900 } else if constexpr (std::is_same_v<T, double>) {
901 if (type == HELIOS_TYPE_DOUBLE) {
902 data = object_data_double.at(label).front();
903 } else {
904 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type double, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type double.");
905 }
906 } else if constexpr (std::is_same_v<T, vec2>) {
907 if (type == HELIOS_TYPE_VEC2) {
908 data = object_data_vec2.at(label).front();
909 } else {
910 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec2.");
911 }
912 } else if constexpr (std::is_same_v<T, vec3>) {
913 if (type == HELIOS_TYPE_VEC3) {
914 data = object_data_vec3.at(label).front();
915 } else {
916 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec3.");
917 }
918 } else if constexpr (std::is_same_v<T, vec4>) {
919 if (type == HELIOS_TYPE_VEC4) {
920 data = object_data_vec4.at(label).front();
921 } else {
922 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec4.");
923 }
924 } else if constexpr (std::is_same_v<T, int2>) {
925 if (type == HELIOS_TYPE_INT2) {
926 data = object_data_int2.at(label).front();
927 } else {
928 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int2.");
929 }
930 } else if constexpr (std::is_same_v<T, int3>) {
931 if (type == HELIOS_TYPE_INT3) {
932 data = object_data_int3.at(label).front();
933 } else {
934 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int3.");
935 }
936 } else if constexpr (std::is_same_v<T, int4>) {
937 if (type == HELIOS_TYPE_INT4) {
938 data = object_data_int4.at(label).front();
939 } else {
940 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int4.");
941 }
942 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
943 if (type == HELIOS_TYPE_STRING) {
944 data = object_data_string.at(label).front();
945 } else {
946 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type string, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type string.");
947 }
948 }
949 }
950
952
957 template<typename T>
958 void getObjectData(const char *label, std::vector<T> &data) const {
959#ifdef HELIOS_DEBUG
960 if (!doesObjectDataExist(label)) {
961 helios_runtime_error("ERROR (CompoundObject::getObjectData): Object data " + std::string(label) + " does not exist for object " + std::to_string(OID));
962 }
963#endif
964
965 HeliosDataType type = object_data_types.at(label);
966
967 if constexpr (std::is_same_v<T, int>) {
968 if (type == HELIOS_TYPE_INT) {
969 data = object_data_int.at(label);
970 } else {
971 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int.");
972 }
973 } else if constexpr (std::is_same_v<T, uint>) {
974 if (type == HELIOS_TYPE_UINT) {
975 data = object_data_uint.at(label);
976 } else {
977 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type uint, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type uint.");
978 }
979 } else if constexpr (std::is_same_v<T, float>) {
980 if (type == HELIOS_TYPE_FLOAT) {
981 data = object_data_float.at(label);
982 } else {
983 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type float, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type float.");
984 }
985 } else if constexpr (std::is_same_v<T, double>) {
986 if (type == HELIOS_TYPE_DOUBLE) {
987 data = object_data_double.at(label);
988 } else {
989 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type double, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type double.");
990 }
991 } else if constexpr (std::is_same_v<T, vec2>) {
992 if (type == HELIOS_TYPE_VEC2) {
993 data = object_data_vec2.at(label);
994 } else {
995 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec2.");
996 }
997 } else if constexpr (std::is_same_v<T, vec3>) {
998 if (type == HELIOS_TYPE_VEC3) {
999 data = object_data_vec3.at(label);
1000 } else {
1001 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec3.");
1002 }
1003 } else if constexpr (std::is_same_v<T, vec4>) {
1004 if (type == HELIOS_TYPE_VEC4) {
1005 data = object_data_vec4.at(label);
1006 } else {
1007 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type vec4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type vec4.");
1008 }
1009 } else if constexpr (std::is_same_v<T, int2>) {
1010 if (type == HELIOS_TYPE_INT2) {
1011 data = object_data_int2.at(label);
1012 } else {
1013 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int2, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int2.");
1014 }
1015 } else if constexpr (std::is_same_v<T, int3>) {
1016 if (type == HELIOS_TYPE_INT3) {
1017 data = object_data_int3.at(label);
1018 } else {
1019 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int3, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int3.");
1020 }
1021 } else if constexpr (std::is_same_v<T, int4>) {
1022 if (type == HELIOS_TYPE_INT4) {
1023 data = object_data_int4.at(label);
1024 } else {
1025 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type int4, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type int4.");
1026 }
1027 } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
1028 if (type == HELIOS_TYPE_STRING) {
1029 data = object_data_string.at(label);
1030 } else {
1031 helios_runtime_error("ERROR (CompoundObject::getObjectData): Attempted to get data for type string, but data " + std::string(label) + " for object " + std::to_string(OID) + " does not have type string.");
1032 }
1033 }
1034 }
1035
1037
1042 HeliosDataType getObjectDataType(const char *label) const;
1043
1045
1049 uint getObjectDataSize(const char *label) const;
1050
1052
1056 bool doesObjectDataExist(const char *label) const;
1057
1059
1062 void clearObjectData(const char *label);
1063
1065 [[nodiscard]] std::vector<std::string> listObjectData() const;
1066
1067 protected:
1069 uint OID;
1070
1072 helios::ObjectType type;
1073
1075 std::vector<uint> UUIDs;
1076
1078 helios::Context *context;
1079
1081 std::string texturefile;
1082
1084 float transform[16];
1085
1087 helios::vec3 object_origin;
1088
1090 bool primitivesarecomplete = true;
1091
1092 std::map<std::string, HeliosDataType> object_data_types;
1093 std::map<std::string, std::vector<int>> object_data_int;
1094 std::map<std::string, std::vector<uint>> object_data_uint;
1095 std::map<std::string, std::vector<float>> object_data_float;
1096 std::map<std::string, std::vector<double>> object_data_double;
1097 std::map<std::string, std::vector<vec2>> object_data_vec2;
1098 std::map<std::string, std::vector<vec3>> object_data_vec3;
1099 std::map<std::string, std::vector<vec4>> object_data_vec4;
1100 std::map<std::string, std::vector<int2>> object_data_int2;
1101 std::map<std::string, std::vector<int3>> object_data_int3;
1102 std::map<std::string, std::vector<int4>> object_data_int4;
1103 std::map<std::string, std::vector<std::string>> object_data_string;
1104 std::map<std::string, std::vector<bool>> object_data_bool;
1105
1106 bool ishidden = false;
1107
1108 friend class Context;
1109 };
1110
1112 class Tile final : public CompoundObject {
1113 public:
1115 ~Tile() override = default;
1116
1118 [[nodiscard]] helios::vec2 getSize() const;
1119
1121 [[nodiscard]] helios::vec3 getCenter() const;
1122
1124 [[nodiscard]] helios::int2 getSubdivisionCount() const;
1125
1127
1131 void setSubdivisionCount(const helios::int2 &subdiv);
1132
1134 [[nodiscard]] std::vector<helios::vec3> getVertices() const;
1135
1137 [[nodiscard]] helios::vec3 getNormal() const;
1138
1140 [[nodiscard]] std::vector<helios::vec2> getTextureUV() const;
1141
1142 protected:
1144
1147 Tile(uint a_OID, const std::vector<uint> &a_UUIDs, const int2 &a_subdiv, const char *a_texturefile, helios::Context *a_context);
1148
1149 helios::int2 subdiv;
1150
1151 friend class CompoundObject;
1152 friend class Context;
1153 };
1154
1156 class Sphere final : public CompoundObject {
1157 public:
1159 ~Sphere() override = default;
1160
1162 [[nodiscard]] helios::vec3 getRadius() const;
1163
1165 [[nodiscard]] helios::vec3 getCenter() const;
1166
1168 [[nodiscard]] uint getSubdivisionCount() const;
1169
1171
1174 void setSubdivisionCount(uint subdiv);
1175
1177 [[nodiscard]] float getVolume() const;
1178
1179 protected:
1181
1184 Sphere(uint a_OID, const std::vector<uint> &a_UUIDs, uint a_subdiv, const char *a_texturefile, helios::Context *a_context);
1185
1186 uint subdiv;
1187
1188 friend class CompoundObject;
1189 friend class Context;
1190 };
1191
1193 class Tube final : public CompoundObject {
1194 public:
1196 ~Tube() override = default;
1197
1199 [[nodiscard]] std::vector<helios::vec3> getNodes() const;
1200
1202 [[nodiscard]] uint getNodeCount() const;
1203
1205 [[nodiscard]] std::vector<float> getNodeRadii() const;
1206
1208 [[nodiscard]] std::vector<helios::RGBcolor> getNodeColors() const;
1209
1211 [[nodiscard]] std::vector<std::vector<helios::vec3>> getTriangleVertices() const;
1212
1214 [[nodiscard]] uint getSubdivisionCount() const;
1215
1217 [[nodiscard]] float getLength() const;
1218
1220 [[nodiscard]] float getVolume() const;
1221
1223
1226 [[nodiscard]] float getSegmentVolume(uint segment_index) const;
1227
1229
1234 void appendTubeSegment(const helios::vec3 &node_position, float node_radius, const helios::RGBcolor &node_color);
1235
1237
1243 void appendTubeSegment(const helios::vec3 &node_position, float node_radius, const char *texturefile, const helios::vec2 &textureuv_ufrac);
1244
1246
1249 void scaleTubeGirth(float S);
1250
1252
1255 void setTubeRadii(const std::vector<float> &node_radii);
1256
1258
1261 void scaleTubeLength(float S);
1262
1264
1267 void setTubeNodes(const std::vector<helios::vec3> &node_xyz);
1268
1270
1273 void pruneTubeNodes(uint node_index);
1274
1275 protected:
1277
1280 Tube(uint a_OID, const std::vector<uint> &a_UUIDs, const std::vector<vec3> &a_nodes, const std::vector<float> &a_radius, const std::vector<helios::RGBcolor> &a_colors, const std::vector<std::vector<helios::vec3>> &a_triangle_vertices,
1281 uint a_subdiv, const char *a_texturefile, helios::Context *a_context);
1282
1283 std::vector<helios::vec3> nodes;
1284
1285 std::vector<std::vector<helios::vec3>> triangle_vertices; // first index is the tube segment ring, second index is vertex within segment ring, third index is the vertex within triangle
1286
1287 std::vector<float> radius;
1288
1289 std::vector<helios::RGBcolor> colors;
1290
1291 uint subdiv;
1292
1293 void updateTriangleVertices() const;
1294
1295 friend class CompoundObject;
1296 friend class Context;
1297 };
1298
1300 class Box final : public CompoundObject {
1301 public:
1303 ~Box() override = default;
1304
1306 [[nodiscard]] helios::vec3 getSize() const;
1307
1309 [[nodiscard]] helios::vec3 getCenter() const;
1310
1312 [[nodiscard]] helios::int3 getSubdivisionCount() const;
1313
1315
1318 void setSubdivisionCount(const helios::int3 &subdiv);
1319
1321 [[nodiscard]] float getVolume() const;
1322
1323 protected:
1325
1328 Box(uint a_OID, const std::vector<uint> &a_UUIDs, const int3 &a_subdiv, const char *a_texturefile, helios::Context *a_context);
1329
1330 helios::int3 subdiv;
1331
1332 friend class CompoundObject;
1333 friend class Context;
1334 };
1335
1337 class Disk final : public CompoundObject {
1338 public:
1340 ~Disk() override = default;
1341
1343 [[nodiscard]] helios::vec2 getSize() const;
1344
1346 [[nodiscard]] helios::vec3 getCenter() const;
1347
1349 [[nodiscard]] helios::int2 getSubdivisionCount() const;
1350
1352
1355 void setSubdivisionCount(const helios::int2 &subdiv);
1356
1357 protected:
1359
1362 Disk(uint a_OID, const std::vector<uint> &a_UUIDs, int2 a_subdiv, const char *a_texturefile, helios::Context *a_context);
1363
1364 int2 subdiv;
1365
1366 friend class CompoundObject;
1367 friend class Context;
1368 };
1369
1371 class Polymesh final : public CompoundObject {
1372 public:
1374 ~Polymesh() override = default;
1375
1377 [[nodiscard]] float getVolume() const;
1378
1379 protected:
1381
1384 Polymesh(uint a_OID, const std::vector<uint> &a_UUIDs, const char *a_texturefile, helios::Context *a_context);
1385
1386 friend class CompoundObject;
1387 friend class Context;
1388 };
1389
1391 class Cone final : public CompoundObject {
1392 public:
1394 ~Cone() override = default;
1395
1397
1400 [[nodiscard]] std::vector<helios::vec3> getNodeCoordinates() const;
1401
1403
1407 [[nodiscard]] helios::vec3 getNodeCoordinate(int node_index) const;
1408
1410
1413 [[nodiscard]] std::vector<float> getNodeRadii() const;
1414
1416
1420 [[nodiscard]] float getNodeRadius(int node_index) const;
1421
1423 [[nodiscard]] uint getSubdivisionCount() const;
1424
1426
1429 void setSubdivisionCount(uint subdiv);
1430
1432 [[nodiscard]] helios::vec3 getAxisUnitVector() const;
1433
1435 [[nodiscard]] float getLength() const;
1436
1438
1441 void scaleLength(float S);
1442
1444
1447 void scaleGirth(float S);
1448
1450 [[nodiscard]] float getVolume() const;
1451
1452 protected:
1454
1457 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);
1458
1459 std::vector<helios::vec3> nodes;
1460 std::vector<float> radii;
1461
1462 uint subdiv;
1463
1464 friend class CompoundObject;
1465 friend class Context;
1466 };
1467
1468
1470
1474 class Primitive {
1475 public:
1477
1480 virtual ~Primitive() = 0;
1481
1483
1486 [[nodiscard]] uint getUUID() const;
1487
1489
1492 [[nodiscard]] PrimitiveType getType() const;
1493
1495
1498 void setParentObjectID(uint objID);
1499
1501 [[nodiscard]] uint getParentObjectID() const;
1502
1504 [[nodiscard]] virtual float getArea() const = 0;
1505
1507 [[nodiscard]] virtual helios::vec3 getNormal() const = 0;
1508
1510
1513 void getTransformationMatrix(float (&T)[16]) const;
1514
1516
1519 void setTransformationMatrix(float (&T)[16]);
1520
1522 [[nodiscard]] virtual std::vector<helios::vec3> getVertices() const = 0;
1523
1525 [[nodiscard]] virtual helios::vec3 getCenter() const = 0;
1526
1528 [[nodiscard]] helios::RGBcolor getColor() const;
1529
1531 [[nodiscard]] helios::RGBcolor getColorRGB() const;
1532
1534 [[nodiscard]] helios::RGBAcolor getColorRGBA() const;
1535
1537
1540 void setColor(const helios::RGBcolor &color);
1541
1543
1546 void setColor(const helios::RGBAcolor &color);
1547
1549 [[nodiscard]] bool hasTexture() const;
1550
1552 [[nodiscard]] std::string getTextureFile() const;
1553
1555
1558 void setTextureFile(const char *texture);
1559
1561
1564 [[nodiscard]] std::vector<vec2> getTextureUV();
1565
1566
1568
1571 void setTextureUV(const std::vector<vec2> &uv);
1572
1574 void overrideTextureColor();
1575
1577 void useTextureColor();
1578
1580 [[nodiscard]] bool isTextureColorOverridden() const;
1581
1583
1586 [[nodiscard]] float getSolidFraction() const;
1587
1589
1592 void setSolidFraction(float solidFraction);
1593
1595
1598 void applyTransform(float (&T)[16]);
1599
1601
1604 void translate(const helios::vec3 &shift);
1605
1607
1611 virtual void rotate(float rotation_radians, const char *rotation_axis_xyz_string) = 0;
1612
1614
1618 virtual void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) = 0;
1619
1621
1626 virtual void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) = 0;
1627
1629
1632 void scale(const helios::vec3 &S);
1633
1635
1639 void scale(const helios::vec3 &S, const helios::vec3 &point);
1640
1641 //-------- Primitive Data Methods ---------- //
1642
1644
1649 template<typename T>
1650 void setPrimitiveData(const char *label, const T &data) {
1651 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> ||
1652 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 *>,
1653 "Primitive::setPrimitiveData() was called with an unsupported type.");
1654
1655 if constexpr (std::is_same_v<T, int>) {
1656 primitive_data_int[label] = {data};
1657 primitive_data_types[label] = HELIOS_TYPE_INT;
1658 } else if constexpr (std::is_same_v<T, uint>) {
1659 primitive_data_uint[label] = {data};
1660 primitive_data_types[label] = HELIOS_TYPE_UINT;
1661 } else if constexpr (std::is_same_v<T, float>) {
1662 primitive_data_float[label] = {data};
1663 primitive_data_types[label] = HELIOS_TYPE_FLOAT;
1664 } else if constexpr (std::is_same_v<T, double>) {
1665 primitive_data_double[label] = {data};
1666 primitive_data_types[label] = HELIOS_TYPE_DOUBLE;
1667 } else if constexpr (std::is_same_v<T, vec2>) {
1668 primitive_data_vec2[label] = {data};
1669 primitive_data_types[label] = HELIOS_TYPE_VEC2;
1670 } else if constexpr (std::is_same_v<T, vec3>) {
1671 primitive_data_vec3[label] = {data};
1672 primitive_data_types[label] = HELIOS_TYPE_VEC3;
1673 } else if constexpr (std::is_same_v<T, vec4>) {
1674 primitive_data_vec4[label] = {data};
1675 primitive_data_types[label] = HELIOS_TYPE_VEC4;
1676 } else if constexpr (std::is_same_v<T, int2>) {
1677 primitive_data_int2[label] = {data};
1678 primitive_data_types[label] = HELIOS_TYPE_INT2;
1679 } else if constexpr (std::is_same_v<T, int3>) {
1680 primitive_data_int3[label] = {data};
1681 primitive_data_types[label] = HELIOS_TYPE_INT3;
1682 } else if constexpr (std::is_same_v<T, int4>) {
1683 primitive_data_int4[label] = {data};
1684 primitive_data_types[label] = HELIOS_TYPE_INT4;
1685 } 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 *>) {
1686 primitive_data_string[label] = {data};
1687 primitive_data_types[label] = HELIOS_TYPE_STRING;
1688 }
1689 dirty_flag = true;
1690 }
1691
1693
1698 template<typename T>
1699 void setPrimitiveData(const char *label, const std::vector<T> &data) {
1700 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> ||
1701 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 *>,
1702 "Primitive::setPrimitiveData() was called with an unsupported type.");
1703
1704 if constexpr (std::is_same_v<T, int>) {
1705 primitive_data_int[label] = data;
1706 primitive_data_types[label] = HELIOS_TYPE_INT;
1707 } else if constexpr (std::is_same_v<T, uint>) {
1708 primitive_data_uint[label] = data;
1709 primitive_data_types[label] = HELIOS_TYPE_UINT;
1710 } else if constexpr (std::is_same_v<T, float>) {
1711 primitive_data_float[label] = data;
1712 primitive_data_types[label] = HELIOS_TYPE_FLOAT;
1713 } else if constexpr (std::is_same_v<T, double>) {
1714 primitive_data_double[label] = data;
1715 primitive_data_types[label] = HELIOS_TYPE_DOUBLE;
1716 } else if constexpr (std::is_same_v<T, vec2>) {
1717 primitive_data_vec2[label] = data;
1718 primitive_data_types[label] = HELIOS_TYPE_VEC2;
1719 } else if constexpr (std::is_same_v<T, vec3>) {
1720 primitive_data_vec3[label] = data;
1721 primitive_data_types[label] = HELIOS_TYPE_VEC3;
1722 } else if constexpr (std::is_same_v<T, vec4>) {
1723 primitive_data_vec4[label] = data;
1724 primitive_data_types[label] = HELIOS_TYPE_VEC4;
1725 } else if constexpr (std::is_same_v<T, int2>) {
1726 primitive_data_int2[label] = data;
1727 primitive_data_types[label] = HELIOS_TYPE_INT2;
1728 } else if constexpr (std::is_same_v<T, int3>) {
1729 primitive_data_int3[label] = data;
1730 primitive_data_types[label] = HELIOS_TYPE_INT3;
1731 } else if constexpr (std::is_same_v<T, int4>) {
1732 primitive_data_int4[label] = data;
1733 primitive_data_types[label] = HELIOS_TYPE_INT4;
1734 } 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 *>) {
1735 primitive_data_string[label] = data;
1736 primitive_data_types[label] = HELIOS_TYPE_STRING;
1737 }
1738 dirty_flag = true;
1739 }
1740
1742
1747 template<typename T>
1748 void getPrimitiveData(const char *label, T &data) const {
1749#ifdef HELIOS_DEBUG
1750 if (!doesPrimitiveDataExist(label)) {
1751 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
1752 }
1753#endif
1754 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> ||
1755 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 *>,
1756 "Primitive::getPrimitiveData() was called with an unsupported type.");
1757
1758 HeliosDataType type = primitive_data_types.at(label);
1759
1760 if constexpr (std::is_same_v<T, int>) {
1761 if (type == HELIOS_TYPE_INT) {
1762 data = primitive_data_int.at(label).front();
1763 } else {
1764 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.");
1765 }
1766 } else if constexpr (std::is_same_v<T, uint>) {
1767 if (type == HELIOS_TYPE_UINT) {
1768 data = primitive_data_uint.at(label).front();
1769 } else {
1770 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.");
1771 }
1772 } else if constexpr (std::is_same_v<T, float>) {
1773 if (type == HELIOS_TYPE_FLOAT) {
1774 data = primitive_data_float.at(label).front();
1775 } else {
1776 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.");
1777 }
1778 } else if constexpr (std::is_same_v<T, double>) {
1779 if (type == HELIOS_TYPE_DOUBLE) {
1780 data = primitive_data_double.at(label).front();
1781 } else {
1782 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.");
1783 }
1784 } else if constexpr (std::is_same_v<T, vec2>) {
1785 if (type == HELIOS_TYPE_VEC2) {
1786 data = primitive_data_vec2.at(label).front();
1787 } else {
1788 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.");
1789 }
1790 } else if constexpr (std::is_same_v<T, vec3>) {
1791 if (type == HELIOS_TYPE_VEC3) {
1792 data = primitive_data_vec3.at(label).front();
1793 } else {
1794 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.");
1795 }
1796 } else if constexpr (std::is_same_v<T, vec4>) {
1797 if (type == HELIOS_TYPE_VEC4) {
1798 data = primitive_data_vec4.at(label).front();
1799 } else {
1800 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.");
1801 }
1802 } else if constexpr (std::is_same_v<T, int2>) {
1803 if (type == HELIOS_TYPE_INT2) {
1804 data = primitive_data_int2.at(label).front();
1805 } else {
1806 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.");
1807 }
1808 } else if constexpr (std::is_same_v<T, int3>) {
1809 if (type == HELIOS_TYPE_INT3) {
1810 data = primitive_data_int3.at(label).front();
1811 } else {
1812 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.");
1813 }
1814 } else if constexpr (std::is_same_v<T, int4>) {
1815 if (type == HELIOS_TYPE_INT4) {
1816 data = primitive_data_int4.at(label).front();
1817 } else {
1818 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.");
1819 }
1820 } 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 *>) {
1821 if (type == HELIOS_TYPE_STRING) {
1822 data = primitive_data_string.at(label).front();
1823 } else {
1824 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.");
1825 }
1826 }
1827 }
1828
1830
1835 template<typename T>
1836 void getPrimitiveData(const char *label, std::vector<T> &data) const {
1837#ifdef HELIOS_DEBUG
1838 if (!doesPrimitiveDataExist(label)) {
1839 helios_runtime_error("ERROR (Primitive::getPrimitiveData): Primitive data " + std::string(label) + " does not exist for primitive " + std::to_string(UUID));
1840 }
1841#endif
1842 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> ||
1843 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 *>,
1844 "Primitive::getPrimitiveData() was called with an unsupported type.");
1845
1846 HeliosDataType type = primitive_data_types.at(label);
1847
1848 if constexpr (std::is_same_v<T, int>) {
1849 if (type == HELIOS_TYPE_INT) {
1850 data = primitive_data_int.at(label);
1851 } else {
1852 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.");
1853 }
1854 } else if constexpr (std::is_same_v<T, uint>) {
1855 if (type == HELIOS_TYPE_UINT) {
1856 data = primitive_data_uint.at(label);
1857 } else {
1858 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.");
1859 }
1860 } else if constexpr (std::is_same_v<T, float>) {
1861 if (type == HELIOS_TYPE_FLOAT) {
1862 data = primitive_data_float.at(label);
1863 } else {
1864 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.");
1865 }
1866 } else if constexpr (std::is_same_v<T, double>) {
1867 if (type == HELIOS_TYPE_DOUBLE) {
1868 data = primitive_data_double.at(label);
1869 } else {
1870 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.");
1871 }
1872 } else if constexpr (std::is_same_v<T, vec2>) {
1873 if (type == HELIOS_TYPE_VEC2) {
1874 data = primitive_data_vec2.at(label);
1875 } else {
1876 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.");
1877 }
1878 } else if constexpr (std::is_same_v<T, vec3>) {
1879 if (type == HELIOS_TYPE_VEC3) {
1880 data = primitive_data_vec3.at(label);
1881 } else {
1882 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.");
1883 }
1884 } else if constexpr (std::is_same_v<T, vec4>) {
1885 if (type == HELIOS_TYPE_VEC4) {
1886 data = primitive_data_vec4.at(label);
1887 } else {
1888 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.");
1889 }
1890 } else if constexpr (std::is_same_v<T, int2>) {
1891 if (type == HELIOS_TYPE_INT2) {
1892 data = primitive_data_int2.at(label);
1893 } else {
1894 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.");
1895 }
1896 } else if constexpr (std::is_same_v<T, int3>) {
1897 if (type == HELIOS_TYPE_INT3) {
1898 data = primitive_data_int3.at(label);
1899 } else {
1900 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.");
1901 }
1902 } else if constexpr (std::is_same_v<T, int4>) {
1903 if (type == HELIOS_TYPE_INT4) {
1904 data = primitive_data_int4.at(label);
1905 } else {
1906 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.");
1907 }
1908 } 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 *>) {
1909 if (type == HELIOS_TYPE_STRING) {
1910 data = primitive_data_string.at(label);
1911 } else {
1912 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.");
1913 }
1914 }
1915 }
1916
1918
1923 HeliosDataType getPrimitiveDataType(const char *label) const;
1924
1926
1930 uint getPrimitiveDataSize(const char *label) const;
1931
1933
1937 bool doesPrimitiveDataExist(const char *label) const;
1938
1940
1943 void clearPrimitiveData(const char *label);
1944
1946 [[nodiscard]] std::vector<std::string> listPrimitiveData() const;
1947
1948 protected:
1950 uint UUID;
1951
1953 PrimitiveType prim_type;
1954
1956 uint parent_object_ID;
1957
1959
1960 uint materialID;
1961
1963 Context *context_ptr;
1964
1966 float transform[16];
1967
1969 std::vector<vec2> uv;
1970
1972 float solid_fraction;
1973
1975 bool dirty_flag;
1976
1977 std::map<std::string, HeliosDataType> primitive_data_types;
1978 std::map<std::string, std::vector<int>> primitive_data_int;
1979 std::map<std::string, std::vector<uint>> primitive_data_uint;
1980 std::map<std::string, std::vector<float>> primitive_data_float;
1981 std::map<std::string, std::vector<double>> primitive_data_double;
1982 std::map<std::string, std::vector<vec2>> primitive_data_vec2;
1983 std::map<std::string, std::vector<vec3>> primitive_data_vec3;
1984 std::map<std::string, std::vector<vec4>> primitive_data_vec4;
1985 std::map<std::string, std::vector<int2>> primitive_data_int2;
1986 std::map<std::string, std::vector<int3>> primitive_data_int3;
1987 std::map<std::string, std::vector<int4>> primitive_data_int4;
1988 std::map<std::string, std::vector<std::string>> primitive_data_string;
1989 std::map<std::string, std::vector<bool>> primitive_data_bool;
1990
1991 bool ishidden = false;
1992
1993 friend class Context;
1994 };
1995
1996
1998
2003 class Patch : public Primitive {
2004 public:
2006 ~Patch() override = default;
2007
2009
2012 [[nodiscard]] float getArea() const override;
2013
2015
2018 [[nodiscard]] helios::vec3 getNormal() const override;
2019
2021
2024 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
2025
2027
2030 [[nodiscard]] helios::vec2 getSize() const;
2031
2033
2036 [[nodiscard]] helios::vec3 getCenter() const override;
2037
2039
2043 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
2044
2046
2050 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
2051
2053
2058 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
2059
2060 protected:
2062
2068 Patch(const helios::RGBAcolor &color, uint parent_objID, uint UUID);
2069
2071
2078 Patch(const char *texturefile, float solid_fraction, uint parent_objID, uint UUID);
2079
2081
2089 Patch(const char *texturefile, const std::vector<helios::vec2> &uv, std::map<std::string, Texture> &textures, uint parent_objID, uint UUID);
2090
2091
2092 friend class Primitive;
2093 friend class Context;
2094 };
2095
2097
2102 class Triangle : public Primitive {
2103 public:
2105 ~Triangle() override = default;
2106
2108
2111 [[nodiscard]] float getArea() const override;
2112
2114
2117 [[nodiscard]] helios::vec3 getNormal() const override;
2118
2120
2123 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
2124
2126
2130 [[nodiscard]] helios::vec3 getVertex(int vertex_index) const;
2131
2133
2136 [[nodiscard]] helios::vec3 getCenter() const override;
2137
2139
2143 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
2144
2146
2150 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
2151
2153
2158 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
2159
2161
2166 void setVertices(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2167
2168 private:
2170
2179 Triangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBAcolor &color, uint parent_objID, uint UUID);
2180
2182
2193 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);
2194
2196
2207 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);
2208
2209 void makeTransformationMatrix(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2210
2211 bool edgeFunction(const helios::vec2 &a, const helios::vec2 &b, const helios::vec2 &c);
2212
2213 friend class Primitive;
2214 friend class Context;
2215 };
2216
2218
2221 class Voxel : public Primitive {
2222 public:
2224 ~Voxel() override = default;
2225
2227
2230 [[nodiscard]] float getArea() const override;
2231
2233 [[nodiscard]] helios::vec3 getNormal() const override;
2234
2236
2239 [[nodiscard]] std::vector<helios::vec3> getVertices() const override;
2240
2242
2245 float getVolume();
2246
2248
2251 [[nodiscard]] helios::vec3 getCenter() const override;
2252
2254
2257 [[nodiscard]] helios::vec3 getSize() const;
2258
2260
2264 void rotate(float rotation_radians, const char *rotation_axis_xyz_string) override;
2265
2267
2271 void rotate(float rotation_radians, const helios::vec3 &rotation_axis_vector) override;
2272
2273
2275
2280 void rotate(float rotation_radians, const helios::vec3 &origin, const helios::vec3 &rotation_axis_vector) override;
2281
2282 protected:
2284
2290 Voxel(const helios::RGBAcolor &color, uint parent_objID, uint UUID);
2291
2292 friend class Primitive;
2293 friend class Context;
2294 };
2295
2298 public:
2300
2305 static int parse_data_float(const pugi::xml_node &node_data, std::vector<float> &data);
2306
2308
2313 static int parse_data_double(const pugi::xml_node &node_data, std::vector<double> &data);
2314
2316
2321 static int parse_data_int(const pugi::xml_node &node_data, std::vector<int> &data);
2322
2324
2329 static int parse_data_uint(const pugi::xml_node &node_data, std::vector<uint> &data);
2330
2332
2337 static int parse_data_string(const pugi::xml_node &node_data, std::vector<std::string> &data);
2338
2340
2345 static int parse_data_vec2(const pugi::xml_node &node_data, std::vector<vec2> &data);
2346
2348
2353 static int parse_data_vec3(const pugi::xml_node &node_data, std::vector<vec3> &data);
2354
2356
2361 static int parse_data_vec4(const pugi::xml_node &node_data, std::vector<vec4> &data);
2362
2364
2369 static int parse_data_int2(const pugi::xml_node &node_data, std::vector<int2> &data);
2370
2372
2377 static int parse_data_int3(const pugi::xml_node &node_data, std::vector<int3> &data);
2378
2380
2385 static int parse_data_int4(const pugi::xml_node &node_data, std::vector<int4> &data);
2386
2388
2393 static int parse_objID(const pugi::xml_node &node_data, uint &objID);
2394
2396
2401 static int parse_transform(const pugi::xml_node &node_data, float (&transform)[16]);
2402
2404
2409 static int parse_texture(const pugi::xml_node &node_data, std::string &texture);
2410
2412
2417 static int parse_textureUV(const pugi::xml_node &node_data, std::vector<vec2> &uvs);
2418
2420
2425 static int parse_solid_fraction(const pugi::xml_node &node_data, float &solid_fraction);
2426
2428
2433 static int parse_vertices(const pugi::xml_node &node_data, std::vector<float> &vertices);
2434
2436
2441 static int parse_subdivisions(const pugi::xml_node &node_data, uint &subdivisions);
2442
2444
2449 static int parse_subdivisions(const pugi::xml_node &node_data, int2 &subdivisions);
2450
2452
2457 static int parse_subdivisions(const pugi::xml_node &node_data, int3 &subdivisions);
2458
2460
2465 static int parse_nodes(const pugi::xml_node &node_data, std::vector<vec3> &nodes);
2466
2468
2473 static int parse_radius(const pugi::xml_node &node_data, std::vector<float> &radius);
2474 };
2475
2477
2480 class Context {
2481 friend class Primitive; // Allow Primitive methods to access private material data
2482
2483 private:
2484 //---------- PRIMITIVE/OBJECT HELIOS::VECTORS ----------------//
2485
2487
2491 [[nodiscard]] Primitive *getPrimitivePointer_private(uint UUID) const;
2492
2494
2498 [[nodiscard]] Patch *getPatchPointer_private(uint UUID) const;
2499
2500
2502
2506 [[nodiscard]] Triangle *getTrianglePointer_private(uint UUID) const;
2507
2509
2513 [[nodiscard]] Voxel *getVoxelPointer_private(uint UUID) const;
2514
2516
2520 [[nodiscard]] CompoundObject *getObjectPointer_private(uint ObjID) const;
2521
2523
2527 [[nodiscard]] Tile *getTileObjectPointer_private(uint ObjID) const;
2528
2530
2534 [[nodiscard]] Sphere *getSphereObjectPointer_private(uint ObjID) const;
2535
2537
2541 [[nodiscard]] Tube *getTubeObjectPointer_private(uint ObjID) const;
2542
2544
2548 [[nodiscard]] Box *getBoxObjectPointer_private(uint ObjID) const;
2549
2551
2555 [[nodiscard]] Disk *getDiskObjectPointer_private(uint ObjID) const;
2556
2558
2562 [[nodiscard]] Polymesh *getPolymeshObjectPointer_private(uint ObjID) const;
2563
2565
2569 [[nodiscard]] Cone *getConeObjectPointer_private(uint ObjID) const;
2570
2572 void invalidateAllUUIDsCache() const {
2573 all_uuids_cache_valid = false;
2574 }
2575
2577
2580 std::unordered_map<uint, Primitive *> primitives;
2581
2583 mutable std::vector<uint> cached_all_uuids;
2585 mutable bool all_uuids_cache_valid = false;
2586
2588 mutable WarningAggregator api_warnings;
2589
2591 std::vector<uint> dirty_deleted_primitives;
2592
2594 std::unordered_map<uint, CompoundObject *> objects;
2595
2597 std::map<std::string, std::vector<float>> timeseries_data;
2598
2600
2601 std::map<std::string, std::vector<double>> timeseries_datevalue;
2602
2603 //------------ TEXTURES ----------------//
2604
2605 std::map<std::string, Texture> textures;
2606
2607 void addTexture(const char *texture_file);
2608
2609
2610 bool doesTextureFileExist(const char *texture_file) const;
2611
2612 bool validateTextureFileExtenstion(const char *texture_file) const;
2613
2614 //------------ MATERIALS ----------------//
2615
2617 static constexpr const char *DEFAULT_MATERIAL_LABEL = "__default__";
2618
2620 std::map<uint, Material> materials;
2621
2623 std::map<std::string, uint> material_label_to_id;
2624
2626 uint currentMaterialID;
2627
2629
2636 uint addMaterial_internal(const std::string &label, const RGBAcolor &color, const std::string &texture = "");
2637
2639 std::string generateMaterialLabel(const RGBAcolor &color, const std::string &texture, bool texture_override) const;
2640
2642 bool isMaterialShared(uint materialID) const;
2643
2645 uint copyMaterialForPrimitive(uint primitiveUUID);
2646
2647 //----------- GLOBAL DATA -------------//
2648
2649 std::map<std::string, GlobalData> globaldata;
2650
2651 std::unordered_map<std::string, size_t> primitive_data_label_counts;
2652 std::unordered_map<std::string, size_t> object_data_label_counts;
2653
2654 //----------- DATA TYPE CONSISTENCY REGISTRIES -------------//
2655
2657 std::unordered_map<std::string, HeliosDataType> primitive_data_type_registry;
2658
2660 std::unordered_map<std::string, HeliosDataType> object_data_type_registry;
2661
2662 //----------- VALUE-LEVEL CACHING REGISTRIES -------------//
2663
2665 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> primitive_string_value_registry;
2666 std::unordered_map<std::string, std::unordered_map<int, size_t>> primitive_int_value_registry;
2667 std::unordered_map<std::string, std::unordered_map<uint, size_t>> primitive_uint_value_registry;
2668
2670 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> object_string_value_registry;
2671 std::unordered_map<std::string, std::unordered_map<int, size_t>> object_int_value_registry;
2672 std::unordered_map<std::string, std::unordered_map<uint, size_t>> object_uint_value_registry;
2673
2675 std::unordered_set<std::string> cached_primitive_data_labels;
2676 std::unordered_set<std::string> cached_object_data_labels;
2677
2679
2682 void incrementPrimitiveDataLabelCounter(const std::string &primitive_data_label);
2683
2685
2688 void decrementPrimitiveDataLabelCounter(const std::string &primitive_data_label);
2689
2690
2692
2695 void incrementObjectDataLabelCounter(const std::string &object_data_label);
2696
2698
2701 void decrementObjectDataLabelCounter(const std::string &object_data_label);
2702
2704 std::string dataTypeToString(HeliosDataType type) const;
2705
2707 bool isTypeCastingSupported(HeliosDataType from_type, HeliosDataType to_type) const;
2708
2709 //---------- CONTEXT PRIVATE MEMBER VARIABLES ---------//
2710
2712
2715 helios::Date sim_date;
2716
2718
2721 helios::Time sim_time;
2722
2724 helios::Location sim_location;
2725
2727 std::minstd_rand0 generator;
2728
2730 std::uniform_real_distribution<float> unif_distribution;
2731
2733 std::normal_distribution<float> norm_distribution;
2734
2735 //---------- CONTEXT I/O ---------//
2736
2737 std::vector<std::string> XMLfiles;
2738
2739 struct OBJmaterial {
2740
2741 RGBcolor color;
2742 std::string texture;
2743 uint materialID;
2744 bool textureHasTransparency = false;
2745 bool textureColorIsOverridden = false;
2746
2747 OBJmaterial(const RGBcolor &a_color, std::string a_texture, uint a_materialID) : color{a_color}, texture{std::move(a_texture)}, materialID{a_materialID} {};
2748 };
2749
2750 std::map<std::string, OBJmaterial> loadMTL(const std::string &filebase, const std::string &material_file, const RGBcolor &default_color);
2751
2752 void loadMaterialData(pugi::xml_node mat_node, const std::string &material_label);
2753
2754 void loadPData(pugi::xml_node p, uint UUID);
2755
2756 void loadOData(pugi::xml_node p, uint ID);
2757
2758 void loadOsubPData(pugi::xml_node p, uint ID);
2759
2760 void writeDataToXMLstream(const char *data_group, const std::vector<std::string> &data_labels, void *ptr, std::ofstream &outfile) const;
2761
2762
2763 //---------- CONTEXT INITIALIZATION FLAGS ---------//
2764
2765 uint currentUUID;
2766
2767 uint currentObjectID;
2768
2769 //---------- MEMORY HANDLING -----------------//
2770
2772
2776 static void out_of_memory_handler();
2777
2779
2782 static void install_out_of_memory_handler();
2783
2784 public:
2786 Context();
2787
2789 ~Context();
2790
2792 Context(const Context &) = delete;
2793
2795 void operator=(const Context &) = delete;
2796
2798
2803 static int selfTest(int argc, char **argv);
2804
2806
2809 void seedRandomGenerator(uint seed);
2810
2812
2815 std::minstd_rand0 *getRandomGenerator();
2816
2818
2822 void markGeometryClean();
2823
2825
2829 void markGeometryDirty();
2830
2832
2836 [[nodiscard]] bool isGeometryDirty() const;
2837
2839
2842 void markPrimitiveDirty(uint UUID) const;
2843
2845
2848 void markPrimitiveDirty(const std::vector<uint> &UUIDs) const;
2849
2851
2854 void markPrimitiveClean(uint UUID) const;
2855
2857
2860 void markPrimitiveClean(const std::vector<uint> &UUIDs) const;
2861
2863
2867 [[nodiscard]] bool isPrimitiveDirty(uint UUID) const;
2868
2870
2873 uint addPatch();
2874
2876
2883 uint addPatch(const helios::vec3 &center, const helios::vec2 &size);
2884
2886
2894 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
2895
2897
2904 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
2905
2907
2913 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
2914
2916
2924 uint addPatch(const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
2925
2927
2937 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);
2938
2940
2947 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
2948
2950
2958 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBcolor &color);
2959
2961
2969 uint addTriangle(const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2, const helios::RGBAcolor &color);
2970
2972
2984 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);
2985
2987
2994 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size);
2995
2997
3005 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation);
3006
3008
3015 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation, const helios::RGBcolor &color);
3016
3018
3025 uint addVoxel(const helios::vec3 &center, const helios::vec3 &size, const float &rotation, const helios::RGBAcolor &color);
3026
3028
3032 void translatePrimitive(uint UUID, const vec3 &shift);
3033
3035
3039 void translatePrimitive(const std::vector<uint> &UUIDs, const vec3 &shift);
3040
3042
3047 void rotatePrimitive(uint UUID, float rotation_rad, const char *axis);
3048
3050
3055 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const char *axis);
3056
3058
3063 void rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &axis);
3064
3066
3071 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const vec3 &axis);
3072
3074
3080 void rotatePrimitive(uint UUID, float rotation_rad, const helios::vec3 &origin, const helios::vec3 &axis);
3081
3083
3089 void rotatePrimitive(const std::vector<uint> &UUIDs, float rotation_rad, const helios::vec3 &origin, const vec3 &axis);
3090
3092
3097 void setPrimitiveNormal(uint UUID, const helios::vec3 &origin, const helios::vec3 &new_normal);
3098
3100
3105 void setPrimitiveNormal(const std::vector<uint> &UUIDs, const helios::vec3 &origin, const vec3 &new_normal);
3106
3108
3113 void setPrimitiveElevation(uint UUID, const helios::vec3 &origin, float new_elevation);
3114
3116
3121 void setPrimitiveAzimuth(uint UUID, const helios::vec3 &origin, float new_azimuth);
3122
3124
3128 void scalePrimitive(uint UUID, const helios::vec3 &S);
3129
3131
3135 void scalePrimitive(const std::vector<uint> &UUIDs, const helios::vec3 &S);
3136
3138
3143 void scalePrimitiveAboutPoint(uint UUID, const helios::vec3 &S, const helios::vec3 &point);
3144
3146
3151 void scalePrimitiveAboutPoint(const std::vector<uint> &UUIDs, const helios::vec3 &S, const helios::vec3 &point);
3152
3154
3157 void deletePrimitive(uint UUID);
3158
3160
3163 void deletePrimitive(const std::vector<uint> &UUIDs);
3164
3166
3170 uint copyPrimitive(uint UUID);
3171
3173
3177 std::vector<uint> copyPrimitive(const std::vector<uint> &UUIDs);
3178
3180
3184 void copyPrimitiveData(uint sourceUUID, uint destinationUUID);
3185
3187
3192 void renamePrimitiveData(uint UUID, const char *old_label, const char *new_label);
3193
3195
3200 void duplicatePrimitiveData(uint UUID, const char *old_label, const char *new_label);
3201
3203
3206 [[nodiscard]] bool doesPrimitiveExist(uint UUID) const;
3207
3209
3213 [[nodiscard]] bool doesPrimitiveExist(const std::vector<uint> &UUIDs) const;
3214
3216
3221 [[nodiscard]] helios::vec2 getPatchSize(uint UUID) const;
3222
3224
3229 [[nodiscard]] helios::vec3 getPatchCenter(uint UUID) const;
3230
3232
3238 [[nodiscard]] helios::vec3 getTriangleVertex(uint UUID, uint number) const;
3239
3241
3247 void setTriangleVertices(uint UUID, const helios::vec3 &vertex0, const helios::vec3 &vertex1, const helios::vec3 &vertex2);
3248
3250
3255 [[nodiscard]] helios::vec3 getVoxelCenter(uint UUID) const;
3256
3258
3263 [[nodiscard]] helios::vec3 getVoxelSize(uint UUID) const;
3264
3266
3270 [[nodiscard]] size_t getPrimitiveCount(bool include_hidden_primitives = true) const;
3271
3273
3277 [[nodiscard]] size_t getTriangleCount(bool include_hidden_primitives = true) const;
3278
3280
3284 [[nodiscard]] size_t getPatchCount(bool include_hidden_primitives = true) const;
3285
3287 [[nodiscard]] std::vector<uint> getAllUUIDs() const;
3288
3290
3294 [[nodiscard]] std::vector<uint> getDirtyUUIDs(bool include_deleted_UUIDs = false) const;
3295
3297
3300 [[nodiscard]] std::vector<uint> getDeletedUUIDs() const;
3301
3303
3306 void hidePrimitive(uint UUID) const;
3307
3309
3312 void hidePrimitive(const std::vector<uint> &UUIDs) const;
3313
3315
3318 void showPrimitive(uint UUID) const;
3319
3321
3324 void showPrimitive(const std::vector<uint> &UUIDs) const;
3325
3327
3331 [[nodiscard]] bool isPrimitiveHidden(uint UUID) const;
3332
3334
3337 void cleanDeletedUUIDs(std::vector<uint> &UUIDs) const;
3338
3340
3343 void cleanDeletedUUIDs(std::vector<std::vector<uint>> &UUIDs) const;
3344
3346
3349 void cleanDeletedUUIDs(std::vector<std::vector<std::vector<uint>>> &UUIDs) const;
3350
3351 //-------- Primitive Data Methods ---------- //
3352
3354
3360 template<typename T>
3361 void setPrimitiveData(uint UUID, const char *label, const T &data) {
3362#ifdef HELIOS_DEBUG
3363 if (primitives.find(UUID) == primitives.end()) {
3364 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3365 }
3366#endif
3367 // Check if this primitive already has cached data for registry maintenance
3368 std::string label_str = std::string(label);
3369 bool had_cached_value = false;
3370
3371 // Handle caching only for supported types, and avoid character arrays
3372 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3373 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3374 T old_cached_value{};
3375 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
3376 decrementPrimitiveValueRegistry(label_str, old_cached_value);
3377 had_cached_value = true;
3378 }
3379 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3380 if (isPrimitiveDataValueCachingEnabled(label_str) && primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3381 std::string old_cached_value;
3382 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
3383 decrementPrimitiveValueRegistry(label_str, old_cached_value);
3384 had_cached_value = true;
3385 }
3386 }
3387
3388 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3389 incrementPrimitiveDataLabelCounter(label);
3390 }
3391
3392 // Validate data type consistency and register/validate type
3393 HeliosDataType data_type;
3394 if constexpr (std::is_same_v<T, int>) {
3395 data_type = HELIOS_TYPE_INT;
3396 } else if constexpr (std::is_same_v<T, uint>) {
3397 data_type = HELIOS_TYPE_UINT;
3398 } else if constexpr (std::is_same_v<T, float>) {
3399 data_type = HELIOS_TYPE_FLOAT;
3400 } else if constexpr (std::is_same_v<T, double>) {
3401 data_type = HELIOS_TYPE_DOUBLE;
3402 } else if constexpr (std::is_same_v<T, vec2>) {
3403 data_type = HELIOS_TYPE_VEC2;
3404 } else if constexpr (std::is_same_v<T, vec3>) {
3405 data_type = HELIOS_TYPE_VEC3;
3406 } else if constexpr (std::is_same_v<T, vec4>) {
3407 data_type = HELIOS_TYPE_VEC4;
3408 } else if constexpr (std::is_same_v<T, int2>) {
3409 data_type = HELIOS_TYPE_INT2;
3410 } else if constexpr (std::is_same_v<T, int3>) {
3411 data_type = HELIOS_TYPE_INT3;
3412 } else if constexpr (std::is_same_v<T, int4>) {
3413 data_type = HELIOS_TYPE_INT4;
3414 } 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 *>) {
3415 data_type = HELIOS_TYPE_STRING;
3416 }
3417 HeliosDataType target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
3418
3419 // Store data with type casting if needed
3420 if (target_type != data_type && isTypeCastingSupported(data_type, target_type)) {
3421 storeDataWithTypeCasting(UUID, label, data, target_type);
3422 } else {
3423 primitives.at(UUID)->setPrimitiveData(label, data);
3424 }
3425
3426 // Update value registry if caching is enabled for this label (only for new data)
3427 if (isPrimitiveDataValueCachingEnabled(label_str) && !had_cached_value) {
3428 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3429 incrementPrimitiveValueRegistry(label_str, data);
3430 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3431 incrementPrimitiveValueRegistry(label_str, std::string(data));
3432 }
3433 } else if (isPrimitiveDataValueCachingEnabled(label_str) && had_cached_value) {
3434 // For updates, just add the new value (old value was already decremented)
3435 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3436 incrementPrimitiveValueRegistry(label_str, data);
3437 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
3438 incrementPrimitiveValueRegistry(label_str, std::string(data));
3439 }
3440 }
3441 }
3442
3444
3450 template<typename T>
3451 void setPrimitiveData(uint UUID, const char *label, const std::vector<T> &data) {
3452#ifdef HELIOS_DEBUG
3453 if (primitives.find(UUID) == primitives.end()) {
3454 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3455 }
3456#endif
3457 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3458 incrementPrimitiveDataLabelCounter(label);
3459 }
3460
3461 // For vector data, register the base type (not vector type)
3462 HeliosDataType data_type;
3463 if constexpr (std::is_same_v<T, int>) {
3464 data_type = HELIOS_TYPE_INT;
3465 } else if constexpr (std::is_same_v<T, uint>) {
3466 data_type = HELIOS_TYPE_UINT;
3467 } else if constexpr (std::is_same_v<T, float>) {
3468 data_type = HELIOS_TYPE_FLOAT;
3469 } else if constexpr (std::is_same_v<T, double>) {
3470 data_type = HELIOS_TYPE_DOUBLE;
3471 } else if constexpr (std::is_same_v<T, vec2>) {
3472 data_type = HELIOS_TYPE_VEC2;
3473 } else if constexpr (std::is_same_v<T, vec3>) {
3474 data_type = HELIOS_TYPE_VEC3;
3475 } else if constexpr (std::is_same_v<T, vec4>) {
3476 data_type = HELIOS_TYPE_VEC4;
3477 } else if constexpr (std::is_same_v<T, int2>) {
3478 data_type = HELIOS_TYPE_INT2;
3479 } else if constexpr (std::is_same_v<T, int3>) {
3480 data_type = HELIOS_TYPE_INT3;
3481 } else if constexpr (std::is_same_v<T, int4>) {
3482 data_type = HELIOS_TYPE_INT4;
3483 } 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 *>) {
3484 data_type = HELIOS_TYPE_STRING;
3485 }
3486 registerOrValidatePrimitiveDataType<T>(label, data_type);
3487
3488 primitives.at(UUID)->setPrimitiveData(label, data);
3489 }
3490
3492
3499 template<typename T>
3500 void setPrimitiveData(const std::vector<uint> &UUIDs, const char *label, const std::vector<T> &data) {
3501#ifdef HELIOS_DEBUG
3502 if (UUIDs.size() != data.size()) {
3503 helios_runtime_error("ERROR (Context::setPrimitiveData): UUIDs and data vectors must be the same size.");
3504 }
3505#endif
3506
3507 // Validate data type consistency and register/validate type (only once for all elements)
3508 HeliosDataType target_type = HELIOS_TYPE_UNKNOWN;
3509 if (!UUIDs.empty()) {
3510 HeliosDataType data_type;
3511 if constexpr (std::is_same_v<T, int>) {
3512 data_type = HELIOS_TYPE_INT;
3513 } else if constexpr (std::is_same_v<T, uint>) {
3514 data_type = HELIOS_TYPE_UINT;
3515 } else if constexpr (std::is_same_v<T, float>) {
3516 data_type = HELIOS_TYPE_FLOAT;
3517 } else if constexpr (std::is_same_v<T, double>) {
3518 data_type = HELIOS_TYPE_DOUBLE;
3519 } else if constexpr (std::is_same_v<T, vec2>) {
3520 data_type = HELIOS_TYPE_VEC2;
3521 } else if constexpr (std::is_same_v<T, vec3>) {
3522 data_type = HELIOS_TYPE_VEC3;
3523 } else if constexpr (std::is_same_v<T, vec4>) {
3524 data_type = HELIOS_TYPE_VEC4;
3525 } else if constexpr (std::is_same_v<T, int2>) {
3526 data_type = HELIOS_TYPE_INT2;
3527 } else if constexpr (std::is_same_v<T, int3>) {
3528 data_type = HELIOS_TYPE_INT3;
3529 } else if constexpr (std::is_same_v<T, int4>) {
3530 data_type = HELIOS_TYPE_INT4;
3531 } 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 *>) {
3532 data_type = HELIOS_TYPE_STRING;
3533 }
3534 target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
3535 }
3536
3537 for (uint UUID: UUIDs) {
3538#ifdef HELIOS_DEBUG
3539 if (primitives.find(UUID) == primitives.end()) {
3540 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3541 }
3542#endif
3543 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3544 incrementPrimitiveDataLabelCounter(label);
3545 }
3546 }
3547
3548#ifdef USE_OPENMP
3549#pragma omp parallel for
3550#endif
3551 for (int i = 0; i < (int) UUIDs.size(); ++i) {
3552 primitives.at(UUIDs[i])->setPrimitiveData(label, data[i]);
3553 }
3554 }
3555
3557
3563 template<typename T>
3564 void setPrimitiveData(const std::vector<uint> &UUIDs, const char *label, const T &data) {
3565
3566 // Validate data type consistency and register/validate type
3567 if (!UUIDs.empty()) {
3568 HeliosDataType data_type;
3569 if constexpr (std::is_same_v<T, int>) {
3570 data_type = HELIOS_TYPE_INT;
3571 } else if constexpr (std::is_same_v<T, uint>) {
3572 data_type = HELIOS_TYPE_UINT;
3573 } else if constexpr (std::is_same_v<T, float>) {
3574 data_type = HELIOS_TYPE_FLOAT;
3575 } else if constexpr (std::is_same_v<T, double>) {
3576 data_type = HELIOS_TYPE_DOUBLE;
3577 } else if constexpr (std::is_same_v<T, vec2>) {
3578 data_type = HELIOS_TYPE_VEC2;
3579 } else if constexpr (std::is_same_v<T, vec3>) {
3580 data_type = HELIOS_TYPE_VEC3;
3581 } else if constexpr (std::is_same_v<T, vec4>) {
3582 data_type = HELIOS_TYPE_VEC4;
3583 } else if constexpr (std::is_same_v<T, int2>) {
3584 data_type = HELIOS_TYPE_INT2;
3585 } else if constexpr (std::is_same_v<T, int3>) {
3586 data_type = HELIOS_TYPE_INT3;
3587 } else if constexpr (std::is_same_v<T, int4>) {
3588 data_type = HELIOS_TYPE_INT4;
3589 } 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 *>) {
3590 data_type = HELIOS_TYPE_STRING;
3591 }
3592 registerOrValidatePrimitiveDataType<T>(label, data_type);
3593 }
3594
3595 for (uint UUID: UUIDs) {
3596#ifdef HELIOS_DEBUG
3597 if (primitives.find(UUID) == primitives.end()) {
3598 helios_runtime_error("ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3599 }
3600#endif
3601 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3602 incrementPrimitiveDataLabelCounter(label);
3603 }
3604 }
3605
3606#ifdef USE_OPENMP
3607#pragma omp parallel for
3608#endif
3609 for (int i = 0; i < (int) UUIDs.size(); ++i) {
3610 primitives.at(UUIDs[i])->setPrimitiveData(label, data);
3611 }
3612 }
3613
3615
3621 template<typename T>
3622 void getPrimitiveData(uint UUID, const char *label, T &data) const {
3623#ifdef HELIOS_DEBUG
3624 if (primitives.find(UUID) == primitives.end()) {
3625 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3626 }
3627#endif
3628 primitives.at(UUID)->getPrimitiveData(label, data);
3629 }
3630
3632
3639 template<typename T>
3640 void getPrimitiveData(uint UUID, const char *label, std::vector<T> &data) const {
3641#ifdef HELIOS_DEBUG
3642 if (primitives.find(UUID) == primitives.end()) {
3643 helios_runtime_error("ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) + " does not exist in the Context.");
3644 }
3645#endif
3646 primitives.at(UUID)->getPrimitiveData(label, data);
3647 }
3648
3650
3656 [[deprecated]]
3657 HeliosDataType getPrimitiveDataType(uint UUID, const char *label) const;
3658
3660
3666 HeliosDataType getPrimitiveDataType(const char *label) const;
3667
3669
3674 uint getPrimitiveDataSize(uint UUID, const char *label) const;
3675
3677
3682 bool doesPrimitiveDataExist(uint UUID, const char *label) const;
3683
3685
3689 void clearPrimitiveData(uint UUID, const char *label);
3690
3692
3696 void clearPrimitiveData(const std::vector<uint> &UUIDs, const char *label);
3697
3699
3702 [[nodiscard]] std::vector<std::string> listAllPrimitiveDataLabels() const;
3703
3704
3705 //----------- VALUE-LEVEL CACHING CONFIGURATION ----------//
3706
3708
3711 void enablePrimitiveDataValueCaching(const std::string &label);
3712
3714
3717 void disablePrimitiveDataValueCaching(const std::string &label);
3718
3720
3724 [[nodiscard]] bool isPrimitiveDataValueCachingEnabled(const std::string &label) const;
3725
3727
3730 void enableObjectDataValueCaching(const std::string &label);
3731
3733
3736 void disableObjectDataValueCaching(const std::string &label);
3737
3739
3743 [[nodiscard]] bool isObjectDataValueCachingEnabled(const std::string &label) const;
3744
3745 //----------- UNIQUE VALUE QUERY METHODS ----------//
3746
3747
3749
3753 [[nodiscard]] PrimitiveType getPrimitiveType(uint UUID) const;
3754
3756
3760 void setPrimitiveParentObjectID(uint UUID, uint objID);
3761
3763
3767 void setPrimitiveParentObjectID(const std::vector<uint> &UUIDs, uint objID);
3768
3770
3773 [[nodiscard]] uint getPrimitiveParentObjectID(uint UUID) const;
3774
3776
3779 [[nodiscard]] std::vector<uint> getPrimitiveParentObjectID(const std::vector<uint> &UUIDs) const;
3780
3782
3785 [[nodiscard]] std::vector<uint> getUniquePrimitiveParentObjectIDs(const std::vector<uint> &UUIDs) const;
3786
3788
3792 [[nodiscard]] std::vector<uint> getUniquePrimitiveParentObjectIDs(const std::vector<uint> &UUIDs, bool include_ObjID_zero) const;
3793
3795
3798 [[nodiscard]] float getPrimitiveArea(uint UUID) const;
3799
3801
3806 void getPrimitiveBoundingBox(uint UUID, vec3 &min_corner, vec3 &max_corner) const;
3807
3809
3814 void getPrimitiveBoundingBox(const std::vector<uint> &UUIDs, vec3 &min_corner, vec3 &max_corner) const;
3815
3817
3820 void hideObject(uint ObjID);
3821
3823
3826 void hideObject(const std::vector<uint> &ObjIDs);
3827
3829
3832 void showObject(uint ObjID);
3833
3835
3838 void showObject(const std::vector<uint> &ObjIDs);
3839
3841
3845 [[nodiscard]] bool isObjectHidden(uint ObjID) const;
3846
3848
3851 [[nodiscard]] float getObjectArea(uint ObjID) const;
3852
3854
3857 [[nodiscard]] helios::vec3 getObjectAverageNormal(uint ObjID) const;
3858
3860
3863 [[nodiscard]] uint getObjectPrimitiveCount(uint ObjID) const;
3864
3866
3869 [[nodiscard]] helios::vec3 getObjectCenter(uint ObjID) const;
3870
3872
3876 void setObjectColor(uint ObjID, const helios::RGBcolor &color) const;
3877
3879
3883 void setObjectColor(const std::vector<uint> &ObjIDs, const helios::RGBcolor &color) const;
3884
3886
3890 void setObjectColor(uint ObjID, const helios::RGBAcolor &color) const;
3891
3893
3897 void setObjectColor(const std::vector<uint> &ObjIDs, const helios::RGBAcolor &color) const;
3898
3900
3903 [[nodiscard]] std::string getObjectTextureFile(uint ObjID) const;
3904
3906
3910 void getObjectTransformationMatrix(uint ObjID, float (&T)[16]) const;
3911
3913
3917 void setObjectTransformationMatrix(uint ObjID, float (&T)[16]) const;
3918
3920
3924 void setObjectTransformationMatrix(const std::vector<uint> &ObjIDs, float (&T)[16]) const;
3925
3927
3935 void setObjectAverageNormal(uint ObjID, const vec3 &origin, const vec3 &new_normal) const;
3936
3938
3944 void setObjectOrigin(uint ObjID, const vec3 &origin) const;
3945
3947
3950 [[nodiscard]] bool objectHasTexture(uint ObjID) const;
3951
3953
3957 [[nodiscard]] bool doesObjectContainPrimitive(uint ObjID, uint UUID) const;
3958
3960
3963 void overrideObjectTextureColor(uint ObjID) const;
3964
3966
3969 void overrideObjectTextureColor(const std::vector<uint> &ObjIDs) const;
3970
3973
3976 void useObjectTextureColor(uint ObjID) const;
3977
3980
3983 void useObjectTextureColor(const std::vector<uint> &ObjIDs);
3984
3986
3991 void getObjectBoundingBox(uint ObjID, vec3 &min_corner, vec3 &max_corner) const;
3992
3994
3999 void getObjectBoundingBox(const std::vector<uint> &ObjIDs, vec3 &min_corner, vec3 &max_corner) const;
4000
4002
4005 void printObjectInfo(uint ObjID) const;
4006
4008 [[nodiscard]] std::vector<std::string> listObjectData(uint ObjID) const;
4009
4011 [[nodiscard]] std::vector<std::string> listPrimitiveData(uint UUID) const;
4012
4014
4018 [[nodiscard]] float getPrimitiveSolidFraction(uint UUID) const;
4019
4021
4024 [[nodiscard]] helios::vec3 getPrimitiveNormal(uint UUID) const;
4025
4027
4031 void getPrimitiveTransformationMatrix(uint UUID, float (&T)[16]) const;
4032
4034
4038 void setPrimitiveTransformationMatrix(uint UUID, float (&T)[16]);
4039
4041
4045 void setPrimitiveTransformationMatrix(const std::vector<uint> &UUIDs, float (&T)[16]);
4046
4048
4051 [[nodiscard]] std::vector<helios::vec3> getPrimitiveVertices(uint UUID) const;
4052
4054
4057 [[nodiscard]] helios::RGBcolor getPrimitiveColor(uint UUID) const;
4058
4060
4063 [[nodiscard]] helios::RGBcolor getPrimitiveColorRGB(uint UUID) const;
4064
4066
4069 [[nodiscard]] helios::RGBAcolor getPrimitiveColorRGBA(uint UUID) const;
4070
4072
4076 void setPrimitiveColor(uint UUID, const helios::RGBcolor &color) const;
4077
4079
4083 void setPrimitiveColor(const std::vector<uint> &UUIDs, const helios::RGBcolor &color) const;
4084
4086
4090 void setPrimitiveColor(uint UUID, const helios::RGBAcolor &color) const;
4091
4093
4097 void setPrimitiveColor(const std::vector<uint> &UUIDs, const helios::RGBAcolor &color) const;
4098
4100
4104 [[nodiscard]] std::string getPrimitiveTextureFile(uint UUID) const;
4105
4107
4111 void setPrimitiveTextureFile(uint UUID, const std::string &texturefile) const;
4112
4114
4118 [[nodiscard]] helios::int2 getPrimitiveTextureSize(uint UUID) const;
4119
4121
4124 [[nodiscard]] std::vector<vec2> getPrimitiveTextureUV(uint UUID) const;
4125
4127
4131 [[nodiscard]] bool primitiveTextureHasTransparencyChannel(uint UUID) const;
4132
4134
4138 [[nodiscard]] const std::vector<std::vector<bool>> *getPrimitiveTextureTransparencyData(uint UUID) const;
4139
4141
4144 void overridePrimitiveTextureColor(uint UUID) const;
4145
4147
4150 void overridePrimitiveTextureColor(const std::vector<uint> &UUIDs) const;
4151
4153
4156 void usePrimitiveTextureColor(uint UUID) const;
4157
4159
4162 void usePrimitiveTextureColor(const std::vector<uint> &UUIDs) const;
4163
4165
4168 [[nodiscard]] bool isPrimitiveTextureColorOverridden(uint UUID) const;
4169
4171
4174 void printPrimitiveInfo(uint UUID) const;
4175
4177
4181 void reportAPIWarnings() const;
4182
4183 //-------- Material Management Methods ---------- //
4184
4186
4191 void addMaterial(const std::string &material_label);
4192
4194
4198 [[nodiscard]] bool doesMaterialExist(const std::string &material_label) const;
4199
4201
4204 [[nodiscard]] std::vector<std::string> listMaterials() const;
4205
4207
4211 [[nodiscard]] RGBAcolor getMaterialColor(const std::string &material_label) const;
4212
4214
4218 [[nodiscard]] std::string getMaterialTexture(const std::string &material_label) const;
4219
4221
4225 [[nodiscard]] bool isMaterialTextureColorOverridden(const std::string &material_label) const;
4226
4228
4233 void setMaterialColor(const std::string &material_label, const RGBAcolor &color);
4234
4236
4241 void setMaterialTexture(const std::string &material_label, const std::string &texture_file);
4242
4244
4249 void setMaterialTextureColorOverride(const std::string &material_label, bool override);
4250
4252
4256 [[nodiscard]] uint getMaterialTwosidedFlag(const std::string &material_label) const;
4257
4259
4264 void setMaterialTwosidedFlag(const std::string &material_label, uint twosided_flag);
4265
4267
4274 [[nodiscard]] uint getPrimitiveTwosidedFlag(uint UUID, uint default_value = 1) const;
4275
4277
4282 void assignMaterialToPrimitive(uint UUID, const std::string &material_label);
4283
4285
4290 void assignMaterialToPrimitive(const std::vector<uint> &UUIDs, const std::string &material_label);
4291
4293
4298 void assignMaterialToObject(uint ObjID, const std::string &material_label);
4299
4301
4306 void assignMaterialToObject(const std::vector<uint> &ObjIDs, const std::string &material_label);
4307
4309
4313 [[nodiscard]] std::string getPrimitiveMaterialLabel(uint UUID) const;
4314
4316
4320 [[nodiscard]] std::vector<uint> getPrimitivesUsingMaterial(const std::string &material_label) const;
4321
4323
4328 void deleteMaterial(const std::string &material_label);
4329
4331
4338 template<typename T>
4339 void setMaterialData(const std::string &material_label, const char *data_label, const T &data) {
4340 uint matID = getMaterialIDFromLabel(material_label);
4341 materials[matID].setMaterialData(data_label, data);
4342 }
4343
4345
4352 template<typename T>
4353 void setMaterialData(const std::string &material_label, const char *data_label, const std::vector<T> &data) {
4354 uint matID = getMaterialIDFromLabel(material_label);
4355 materials[matID].setMaterialData(data_label, data);
4356 }
4357
4359
4365 template<typename T>
4366 void getMaterialData(const std::string &material_label, const char *data_label, T &data) const {
4367 uint matID = getMaterialIDFromLabel(material_label);
4368 materials.at(matID).getMaterialData(data_label, data);
4369 }
4370
4372
4378 template<typename T>
4379 void getMaterialData(const std::string &material_label, const char *data_label, std::vector<T> &data) const {
4380 uint matID = getMaterialIDFromLabel(material_label);
4381 materials.at(matID).getMaterialData(data_label, data);
4382 }
4383
4385
4390 [[nodiscard]] bool doesMaterialDataExist(const std::string &material_label, const char *data_label) const;
4391
4393
4398 [[nodiscard]] HeliosDataType getMaterialDataType(const std::string &material_label, const char *data_label) const;
4399
4401
4405 void clearMaterialData(const std::string &material_label, const char *data_label);
4406
4408
4418 template<typename T>
4419 void getDataWithMaterialFallback(uint UUID, const char *data_label, T &data) const {
4420 Primitive *prim = getPrimitivePointer_private(UUID);
4421 uint materialID = prim->materialID;
4422
4423 // First check if material has this data
4424 if (materials.find(materialID) != materials.end() && materials.at(materialID).doesMaterialDataExist(data_label)) {
4425 materials.at(materialID).getMaterialData(data_label, data);
4426 }
4427 // Otherwise check if primitive has this data
4428 else if (prim->doesPrimitiveDataExist(data_label)) {
4429 prim->getPrimitiveData(data_label, data);
4430 }
4431 // If neither has the data, throw error
4432 else {
4433 helios_runtime_error("ERROR (Context::getDataWithMaterialFallback): Data " + std::string(data_label) + " does not exist for primitive " + std::to_string(UUID) + " (neither in its material nor as primitive data).");
4434 }
4435 }
4436
4438
4442 [[nodiscard]] uint getPrimitiveMaterialID(uint UUID) const;
4443
4445
4449 [[nodiscard]] const Material &getMaterial(uint materialID) const;
4450
4452
4456 [[nodiscard]] uint getMaterialIDFromLabel(const std::string &material_label) const;
4457
4459
4462 [[nodiscard]] uint getMaterialCount() const;
4463
4464 //-------- Compound Object Data Methods ---------- //
4465
4467
4473 template<typename T>
4474 void setObjectData(uint objID, const char *label, const T &data) {
4475#ifdef HELIOS_DEBUG
4476 if (objects.find(objID) == objects.end()) {
4477 helios_runtime_error("ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
4478 }
4479#endif
4480 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> ||
4481 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 *>,
4482 "Context::setObjectData() was called with an unsupported type.");
4483
4484 // Validate data type consistency and register/validate type
4485 HeliosDataType data_type;
4486 if constexpr (std::is_same_v<T, int>) {
4487 data_type = HELIOS_TYPE_INT;
4488 } else if constexpr (std::is_same_v<T, uint>) {
4489 data_type = HELIOS_TYPE_UINT;
4490 } else if constexpr (std::is_same_v<T, float>) {
4491 data_type = HELIOS_TYPE_FLOAT;
4492 } else if constexpr (std::is_same_v<T, double>) {
4493 data_type = HELIOS_TYPE_DOUBLE;
4494 } else if constexpr (std::is_same_v<T, vec2>) {
4495 data_type = HELIOS_TYPE_VEC2;
4496 } else if constexpr (std::is_same_v<T, vec3>) {
4497 data_type = HELIOS_TYPE_VEC3;
4498 } else if constexpr (std::is_same_v<T, vec4>) {
4499 data_type = HELIOS_TYPE_VEC4;
4500 } else if constexpr (std::is_same_v<T, int2>) {
4501 data_type = HELIOS_TYPE_INT2;
4502 } else if constexpr (std::is_same_v<T, int3>) {
4503 data_type = HELIOS_TYPE_INT3;
4504 } else if constexpr (std::is_same_v<T, int4>) {
4505 data_type = HELIOS_TYPE_INT4;
4506 } 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 *>) {
4507 data_type = HELIOS_TYPE_STRING;
4508 }
4509 registerOrValidateObjectDataType<T>(label, data_type);
4510
4511 // Check if this object already has cached data for registry maintenance
4512 std::string label_str = std::string(label);
4513 bool had_cached_value = false;
4514
4515 // Handle caching only for supported types, and avoid character arrays
4516 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4517 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
4518 T old_cached_value{};
4519 objects.at(objID)->getObjectData(label, old_cached_value);
4520 decrementObjectValueRegistry(label_str, old_cached_value);
4521 had_cached_value = true;
4522 }
4523 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4524 if (isObjectDataValueCachingEnabled(label_str) && objects.at(objID)->doesObjectDataExist(label)) {
4525 std::string old_cached_value;
4526 objects.at(objID)->getObjectData(label, old_cached_value);
4527 decrementObjectValueRegistry(label_str, old_cached_value);
4528 had_cached_value = true;
4529 }
4530 }
4531
4532 if (!objects.at(objID)->doesObjectDataExist(label)) {
4533 incrementObjectDataLabelCounter(label);
4534 }
4535 objects.at(objID)->setObjectData(label, data);
4536
4537 // Update value registry if caching is enabled for this label (only for new data)
4538 if (isObjectDataValueCachingEnabled(label_str) && !had_cached_value) {
4539 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4540 incrementObjectValueRegistry(label_str, data);
4541 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4542 incrementObjectValueRegistry(label_str, std::string(data));
4543 }
4544 } else if (isObjectDataValueCachingEnabled(label_str) && had_cached_value) {
4545 // For updates, just add the new value (old value was already decremented)
4546 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4547 incrementObjectValueRegistry(label_str, data);
4548 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4549 incrementObjectValueRegistry(label_str, std::string(data));
4550 }
4551 }
4552 }
4553
4555
4561 template<typename T>
4562 void setObjectData(const std::vector<uint> &objIDs, const char *label, const T &data) {
4563 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> ||
4564 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 *>,
4565 "Context::setObjectData() was called with an unsupported type.");
4566
4567 // Validate data type consistency and register/validate type
4568 if (!objIDs.empty()) {
4569 HeliosDataType data_type;
4570 if constexpr (std::is_same_v<T, int>) {
4571 data_type = HELIOS_TYPE_INT;
4572 } else if constexpr (std::is_same_v<T, uint>) {
4573 data_type = HELIOS_TYPE_UINT;
4574 } else if constexpr (std::is_same_v<T, float>) {
4575 data_type = HELIOS_TYPE_FLOAT;
4576 } else if constexpr (std::is_same_v<T, double>) {
4577 data_type = HELIOS_TYPE_DOUBLE;
4578 } else if constexpr (std::is_same_v<T, vec2>) {
4579 data_type = HELIOS_TYPE_VEC2;
4580 } else if constexpr (std::is_same_v<T, vec3>) {
4581 data_type = HELIOS_TYPE_VEC3;
4582 } else if constexpr (std::is_same_v<T, vec4>) {
4583 data_type = HELIOS_TYPE_VEC4;
4584 } else if constexpr (std::is_same_v<T, int2>) {
4585 data_type = HELIOS_TYPE_INT2;
4586 } else if constexpr (std::is_same_v<T, int3>) {
4587 data_type = HELIOS_TYPE_INT3;
4588 } else if constexpr (std::is_same_v<T, int4>) {
4589 data_type = HELIOS_TYPE_INT4;
4590 } 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 *>) {
4591 data_type = HELIOS_TYPE_STRING;
4592 }
4593 registerOrValidateObjectDataType<T>(label, data_type);
4594 }
4595
4596 // Check if caching is enabled for this label
4597 std::string label_str = std::string(label);
4598 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
4599
4600 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
4601 if (caching_enabled) {
4602 // Handle caching only for supported types
4603 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4604 for (uint objID: objIDs) {
4605 if (objects.at(objID)->doesObjectDataExist(label)) {
4606 T old_cached_value{};
4607 objects.at(objID)->getObjectData(label, old_cached_value);
4608 decrementObjectValueRegistry(label_str, old_cached_value);
4609 }
4610 }
4611 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4612 for (uint objID: objIDs) {
4613 if (objects.at(objID)->doesObjectDataExist(label)) {
4614 std::string old_cached_value;
4615 objects.at(objID)->getObjectData(label, old_cached_value);
4616 decrementObjectValueRegistry(label_str, old_cached_value);
4617 }
4618 }
4619 }
4620 }
4621
4622 // Count new data labels
4623 for (uint objID: objIDs) {
4624 if (!objects.at(objID)->doesObjectDataExist(label)) {
4625 incrementObjectDataLabelCounter(label);
4626 }
4627 }
4628
4629#ifdef USE_OPENMP
4630#pragma omp parallel for
4631#endif
4632 for (int i = 0; i < (int) objIDs.size(); ++i) {
4633 objects.at(objIDs[i])->setObjectData(label, data);
4634 }
4635
4636 // Update value registry if caching is enabled (increment the new value for all objects)
4637 if (caching_enabled) {
4638 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4639 // Increment the new value once for each object that received it
4640 for (size_t i = 0; i < objIDs.size(); ++i) {
4641 incrementObjectValueRegistry(label_str, data);
4642 }
4643 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4644 // Increment the new value once for each object that received it
4645 for (size_t i = 0; i < objIDs.size(); ++i) {
4646 incrementObjectValueRegistry(label_str, std::string(data));
4647 }
4648 }
4649 }
4650 }
4651
4653
4659 template<typename T>
4660 void setObjectData(const std::vector<std::vector<uint>> &objIDs, const char *label, const T &data) {
4661 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> ||
4662 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 *>,
4663 "Context::setObjectData() was called with an unsupported type.");
4664
4665 // Validate data type consistency and register/validate type
4666 if (!objIDs.empty() && !objIDs[0].empty()) {
4667 HeliosDataType data_type;
4668 if constexpr (std::is_same_v<T, int>) {
4669 data_type = HELIOS_TYPE_INT;
4670 } else if constexpr (std::is_same_v<T, uint>) {
4671 data_type = HELIOS_TYPE_UINT;
4672 } else if constexpr (std::is_same_v<T, float>) {
4673 data_type = HELIOS_TYPE_FLOAT;
4674 } else if constexpr (std::is_same_v<T, double>) {
4675 data_type = HELIOS_TYPE_DOUBLE;
4676 } else if constexpr (std::is_same_v<T, vec2>) {
4677 data_type = HELIOS_TYPE_VEC2;
4678 } else if constexpr (std::is_same_v<T, vec3>) {
4679 data_type = HELIOS_TYPE_VEC3;
4680 } else if constexpr (std::is_same_v<T, vec4>) {
4681 data_type = HELIOS_TYPE_VEC4;
4682 } else if constexpr (std::is_same_v<T, int2>) {
4683 data_type = HELIOS_TYPE_INT2;
4684 } else if constexpr (std::is_same_v<T, int3>) {
4685 data_type = HELIOS_TYPE_INT3;
4686 } else if constexpr (std::is_same_v<T, int4>) {
4687 data_type = HELIOS_TYPE_INT4;
4688 } 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 *>) {
4689 data_type = HELIOS_TYPE_STRING;
4690 }
4691 registerOrValidateObjectDataType<T>(label, data_type);
4692 }
4693
4694 // Check if caching is enabled for this label
4695 std::string label_str = std::string(label);
4696 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
4697 size_t total_objects = 0;
4698
4699 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
4700 if (caching_enabled) {
4701 // Handle caching only for supported types
4702 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4703 for (const auto &j: objIDs) {
4704 for (uint objID: j) {
4705 total_objects++;
4706 if (objects.at(objID)->doesObjectDataExist(label)) {
4707 T old_cached_value{};
4708 objects.at(objID)->getObjectData(label, old_cached_value);
4709 decrementObjectValueRegistry(label_str, old_cached_value);
4710 }
4711 }
4712 }
4713 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4714 for (const auto &j: objIDs) {
4715 for (uint objID: j) {
4716 total_objects++;
4717 if (objects.at(objID)->doesObjectDataExist(label)) {
4718 std::string old_cached_value;
4719 objects.at(objID)->getObjectData(label, old_cached_value);
4720 decrementObjectValueRegistry(label_str, old_cached_value);
4721 }
4722 }
4723 }
4724 }
4725 } else {
4726 // Count total objects for later cache increment
4727 for (const auto &j: objIDs) {
4728 total_objects += j.size();
4729 }
4730 }
4731
4732 for (const auto &j: objIDs) {
4733 for (uint objID: j) {
4734 if (!objects.at(objID)->doesObjectDataExist(label)) {
4735 incrementObjectDataLabelCounter(label);
4736 }
4737 }
4738 }
4739
4740#ifdef USE_OPENMP
4741#pragma omp parallel for
4742#endif
4743 for (int j = 0; j < (int) objIDs.size(); ++j) {
4744 for (size_t i = 0; i < objIDs[j].size(); ++i) {
4745 objects.at(objIDs[j][i])->setObjectData(label, data);
4746 }
4747 }
4748
4749 // Update value registry if caching is enabled (increment the new value for all objects)
4750 if (caching_enabled) {
4751 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4752 // Increment the new value once for each object that received it
4753 for (size_t i = 0; i < total_objects; ++i) {
4754 incrementObjectValueRegistry(label_str, data);
4755 }
4756 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4757 // Increment the new value once for each object that received it
4758 for (size_t i = 0; i < total_objects; ++i) {
4759 incrementObjectValueRegistry(label_str, std::string(data));
4760 }
4761 }
4762 }
4763 }
4764
4766
4772 template<typename T>
4773 void setObjectData(const std::vector<std::vector<std::vector<uint>>> &objIDs, const char *label, const T &data) {
4774 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> ||
4775 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 *>,
4776 "Context::setObjectData() was called with an unsupported type.");
4777
4778 // Validate data type consistency and register/validate type
4779 if (!objIDs.empty() && !objIDs[0].empty() && !objIDs[0][0].empty()) {
4780 HeliosDataType data_type;
4781 if constexpr (std::is_same_v<T, int>) {
4782 data_type = HELIOS_TYPE_INT;
4783 } else if constexpr (std::is_same_v<T, uint>) {
4784 data_type = HELIOS_TYPE_UINT;
4785 } else if constexpr (std::is_same_v<T, float>) {
4786 data_type = HELIOS_TYPE_FLOAT;
4787 } else if constexpr (std::is_same_v<T, double>) {
4788 data_type = HELIOS_TYPE_DOUBLE;
4789 } else if constexpr (std::is_same_v<T, vec2>) {
4790 data_type = HELIOS_TYPE_VEC2;
4791 } else if constexpr (std::is_same_v<T, vec3>) {
4792 data_type = HELIOS_TYPE_VEC3;
4793 } else if constexpr (std::is_same_v<T, vec4>) {
4794 data_type = HELIOS_TYPE_VEC4;
4795 } else if constexpr (std::is_same_v<T, int2>) {
4796 data_type = HELIOS_TYPE_INT2;
4797 } else if constexpr (std::is_same_v<T, int3>) {
4798 data_type = HELIOS_TYPE_INT3;
4799 } else if constexpr (std::is_same_v<T, int4>) {
4800 data_type = HELIOS_TYPE_INT4;
4801 } 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 *>) {
4802 data_type = HELIOS_TYPE_STRING;
4803 }
4804 registerOrValidateObjectDataType<T>(label, data_type);
4805 }
4806
4807 // Check if caching is enabled for this label
4808 std::string label_str = std::string(label);
4809 bool caching_enabled = isObjectDataValueCachingEnabled(label_str);
4810 size_t total_objects = 0;
4811
4812 // For caching, we need to handle old values before setting new ones (cannot parallelize this part)
4813 if (caching_enabled) {
4814 // Handle caching only for supported types
4815 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4816 for (const auto &k: objIDs) {
4817 for (const auto &j: k) {
4818 for (uint objID: j) {
4819 total_objects++;
4820 if (objects.at(objID)->doesObjectDataExist(label)) {
4821 T old_cached_value{};
4822 objects.at(objID)->getObjectData(label, old_cached_value);
4823 decrementObjectValueRegistry(label_str, old_cached_value);
4824 }
4825 }
4826 }
4827 }
4828 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4829 for (const auto &k: objIDs) {
4830 for (const auto &j: k) {
4831 for (uint objID: j) {
4832 total_objects++;
4833 if (objects.at(objID)->doesObjectDataExist(label)) {
4834 std::string old_cached_value;
4835 objects.at(objID)->getObjectData(label, old_cached_value);
4836 decrementObjectValueRegistry(label_str, old_cached_value);
4837 }
4838 }
4839 }
4840 }
4841 }
4842 } else {
4843 // Count total objects for later cache increment
4844 for (const auto &k: objIDs) {
4845 for (const auto &j: k) {
4846 total_objects += j.size();
4847 }
4848 }
4849 }
4850
4851 for (const auto &k: objIDs) {
4852 for (const auto &j: k) {
4853 for (uint objID: j) {
4854 if (!objects.at(objID)->doesObjectDataExist(label)) {
4855 incrementObjectDataLabelCounter(label);
4856 }
4857 }
4858 }
4859 }
4860
4861#ifdef USE_OPENMP
4862#pragma omp parallel for
4863#endif
4864 for (int k = 0; k < (int) objIDs.size(); ++k) {
4865 for (size_t j = 0; j < objIDs[k].size(); ++j) {
4866 for (size_t i = 0; i < objIDs[k][j].size(); ++i) {
4867 uint objID = objIDs[k][j][i];
4868 objects.at(objID)->setObjectData(label, data);
4869 }
4870 }
4871 }
4872
4873 // Update value registry if caching is enabled (increment the new value for all objects)
4874 if (caching_enabled) {
4875 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4876 // Increment the new value once for each object that received it
4877 for (size_t i = 0; i < total_objects; ++i) {
4878 incrementObjectValueRegistry(label_str, data);
4879 }
4880 } else if constexpr (std::is_same_v<std::decay_t<T>, const char *> || std::is_same_v<std::decay_t<T>, char *>) {
4881 // Increment the new value once for each object that received it
4882 for (size_t i = 0; i < total_objects; ++i) {
4883 incrementObjectValueRegistry(label_str, std::string(data));
4884 }
4885 }
4886 }
4887 }
4888
4890
4897 template<typename T>
4898 void setObjectData(uint objID, const char *label, const std::vector<T> &data) {
4899#ifdef HELIOS_DEBUG
4900 if (objects.find(objID) == objects.end()) {
4901 helios_runtime_error("ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
4902 }
4903#endif
4904 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> ||
4905 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 *>,
4906 "Context::setObjectData() was called with an unsupported type.");
4907
4908 // Validate data type consistency and register/validate type
4909 HeliosDataType data_type;
4910 if constexpr (std::is_same_v<T, int>) {
4911 data_type = HELIOS_TYPE_INT;
4912 } else if constexpr (std::is_same_v<T, uint>) {
4913 data_type = HELIOS_TYPE_UINT;
4914 } else if constexpr (std::is_same_v<T, float>) {
4915 data_type = HELIOS_TYPE_FLOAT;
4916 } else if constexpr (std::is_same_v<T, double>) {
4917 data_type = HELIOS_TYPE_DOUBLE;
4918 } else if constexpr (std::is_same_v<T, vec2>) {
4919 data_type = HELIOS_TYPE_VEC2;
4920 } else if constexpr (std::is_same_v<T, vec3>) {
4921 data_type = HELIOS_TYPE_VEC3;
4922 } else if constexpr (std::is_same_v<T, vec4>) {
4923 data_type = HELIOS_TYPE_VEC4;
4924 } else if constexpr (std::is_same_v<T, int2>) {
4925 data_type = HELIOS_TYPE_INT2;
4926 } else if constexpr (std::is_same_v<T, int3>) {
4927 data_type = HELIOS_TYPE_INT3;
4928 } else if constexpr (std::is_same_v<T, int4>) {
4929 data_type = HELIOS_TYPE_INT4;
4930 } 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 *>) {
4931 data_type = HELIOS_TYPE_STRING;
4932 }
4933 registerOrValidateObjectDataType<T>(label, data_type);
4934
4935 objects.at(objID)->setObjectData(label, data);
4936 }
4937
4939
4946 template<typename T>
4947 void setObjectData(const std::vector<uint> &objIDs, const char *label, const std::vector<T> &data) {
4948#ifdef HELIOS_DEBUG
4949 if (objIDs.size() != data.size()) {
4950 helios_runtime_error("ERROR (Context::setObjectData): Object IDs and data vectors must be the same size.");
4951 }
4952#endif
4953 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> ||
4954 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 *>,
4955 "Context::setObjectData() was called with an unsupported type.");
4956
4957 // Validate data type consistency and register/validate type
4958 if (!objIDs.empty()) {
4959 HeliosDataType data_type;
4960 if constexpr (std::is_same_v<T, int>) {
4961 data_type = HELIOS_TYPE_INT;
4962 } else if constexpr (std::is_same_v<T, uint>) {
4963 data_type = HELIOS_TYPE_UINT;
4964 } else if constexpr (std::is_same_v<T, float>) {
4965 data_type = HELIOS_TYPE_FLOAT;
4966 } else if constexpr (std::is_same_v<T, double>) {
4967 data_type = HELIOS_TYPE_DOUBLE;
4968 } else if constexpr (std::is_same_v<T, vec2>) {
4969 data_type = HELIOS_TYPE_VEC2;
4970 } else if constexpr (std::is_same_v<T, vec3>) {
4971 data_type = HELIOS_TYPE_VEC3;
4972 } else if constexpr (std::is_same_v<T, vec4>) {
4973 data_type = HELIOS_TYPE_VEC4;
4974 } else if constexpr (std::is_same_v<T, int2>) {
4975 data_type = HELIOS_TYPE_INT2;
4976 } else if constexpr (std::is_same_v<T, int3>) {
4977 data_type = HELIOS_TYPE_INT3;
4978 } else if constexpr (std::is_same_v<T, int4>) {
4979 data_type = HELIOS_TYPE_INT4;
4980 } 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 *>) {
4981 data_type = HELIOS_TYPE_STRING;
4982 }
4983 registerOrValidateObjectDataType<T>(label, data_type);
4984 }
4985
4986 for (uint objID: objIDs) {
4987 if (!objects.at(objID)->doesObjectDataExist(label)) {
4988 incrementObjectDataLabelCounter(label);
4989 }
4990 }
4991
4992#ifdef USE_OPENMP
4993#pragma omp parallel for
4994#endif
4995 for (int i = 0; i < (int) objIDs.size(); ++i) {
4996 objects.at(objIDs[i])->setObjectData(label, data[i]);
4997 }
4998 }
4999
5001
5008 void setObjectDataFromPrimitiveDataMean(uint objID, const std::string &label);
5009
5011
5017 template<typename T>
5018 void getObjectData(uint objID, const char *label, T &data) const {
5019#ifdef HELIOS_DEBUG
5020 if (objects.find(objID) == objects.end()) {
5021 helios_runtime_error("ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
5022 }
5023#endif
5024 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> ||
5025 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 *>,
5026 "Context::getObjectData() was called with an unsupported type.");
5027 objects.at(objID)->getObjectData(label, data);
5028 }
5029
5031
5038 template<typename T>
5039 void getObjectData(uint objID, const char *label, std::vector<T> &data) const {
5040#ifdef HELIOS_DEBUG
5041 if (objects.find(objID) == objects.end()) {
5042 helios_runtime_error("ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) + " does not exist in the Context.");
5043 }
5044#endif
5045 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> ||
5046 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 *>,
5047 "Context::getObjectData() was called with an unsupported type.");
5048 objects.at(objID)->getObjectData(label, data);
5049 }
5050
5052
5058 [[deprecated]]
5059 HeliosDataType getObjectDataType(uint objID, const char *label) const;
5060
5062
5068 HeliosDataType getObjectDataType(const char *label) const;
5069
5071
5076 uint getObjectDataSize(uint objID, const char *label) const;
5077
5079
5084 bool doesObjectDataExist(uint objID, const char *label) const;
5085
5087
5091 void clearObjectData(uint objID, const char *label);
5092
5094
5098 void clearObjectData(const std::vector<uint> &objIDs, const char *label);
5099
5101
5104 [[nodiscard]] std::vector<std::string> listAllObjectDataLabels() const;
5105
5107
5111 [[nodiscard]] bool areObjectPrimitivesComplete(uint objID) const;
5112
5114
5117 void cleanDeletedObjectIDs(std::vector<uint> &objIDs) const;
5118
5120
5123 void cleanDeletedObjectIDs(std::vector<std::vector<uint>> &objIDs) const;
5124
5126
5129 void cleanDeletedObjectIDs(std::vector<std::vector<std::vector<uint>>> &objIDs) const;
5130
5131 //-------- Global Data Methods ---------- //
5132
5134
5138 template<typename T>
5139 void setGlobalData(const char *label, const T &data) {
5140 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> ||
5141 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>,
5142 "Context::setGlobalData() was called with an unsupported type.");
5143
5144 globaldata[label].size = 1;
5145 if constexpr (std::is_same_v<T, int>) {
5146 globaldata[label].global_data_int = {data};
5147 globaldata[label].type = HELIOS_TYPE_INT;
5148 } else if constexpr (std::is_same_v<T, uint>) {
5149 globaldata[label].global_data_uint = {data};
5150 globaldata[label].type = HELIOS_TYPE_UINT;
5151 } else if constexpr (std::is_same_v<T, float>) {
5152 globaldata[label].global_data_float = {data};
5153 globaldata[label].type = HELIOS_TYPE_FLOAT;
5154 } else if constexpr (std::is_same_v<T, double>) {
5155 globaldata[label].global_data_double = {data};
5156 globaldata[label].type = HELIOS_TYPE_DOUBLE;
5157 } else if constexpr (std::is_same_v<T, vec2>) {
5158 globaldata[label].global_data_vec2 = {data};
5159 globaldata[label].type = HELIOS_TYPE_VEC2;
5160 } else if constexpr (std::is_same_v<T, vec3>) {
5161 globaldata[label].global_data_vec3 = {data};
5162 globaldata[label].type = HELIOS_TYPE_VEC3;
5163 } else if constexpr (std::is_same_v<T, vec4>) {
5164 globaldata[label].global_data_vec4 = {data};
5165 globaldata[label].type = HELIOS_TYPE_VEC4;
5166 } else if constexpr (std::is_same_v<T, int2>) {
5167 globaldata[label].global_data_int2 = {data};
5168 globaldata[label].type = HELIOS_TYPE_INT2;
5169 } else if constexpr (std::is_same_v<T, int3>) {
5170 globaldata[label].global_data_int3 = {data};
5171 globaldata[label].type = HELIOS_TYPE_INT3;
5172 } else if constexpr (std::is_same_v<T, int4>) {
5173 globaldata[label].global_data_int4 = {data};
5174 globaldata[label].type = HELIOS_TYPE_INT4;
5175 } 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 *>) {
5176 globaldata[label].global_data_string = {data};
5177 globaldata[label].type = HELIOS_TYPE_STRING;
5178 } else if constexpr (std::is_same_v<T, bool>) {
5179 globaldata[label].global_data_bool = {data};
5180 globaldata[label].type = HELIOS_TYPE_BOOL;
5181 }
5182 globaldata[label].version++;
5183 }
5184
5186
5190 template<typename T>
5191 void setGlobalData(const char *label, const std::vector<T> &data) {
5192 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> ||
5193 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>,
5194 "Context::setGlobalData() was called with an unsupported type.");
5195
5196 globaldata[label].size = data.size();
5197 if constexpr (std::is_same_v<T, int>) {
5198 globaldata[label].global_data_int = data;
5199 globaldata[label].type = HELIOS_TYPE_INT;
5200 } else if constexpr (std::is_same_v<T, uint>) {
5201 globaldata[label].global_data_uint = data;
5202 globaldata[label].type = HELIOS_TYPE_UINT;
5203 } else if constexpr (std::is_same_v<T, float>) {
5204 globaldata[label].global_data_float = data;
5205 globaldata[label].type = HELIOS_TYPE_FLOAT;
5206 } else if constexpr (std::is_same_v<T, double>) {
5207 globaldata[label].global_data_double = data;
5208 globaldata[label].type = HELIOS_TYPE_DOUBLE;
5209 } else if constexpr (std::is_same_v<T, vec2>) {
5210 globaldata[label].global_data_vec2 = data;
5211 globaldata[label].type = HELIOS_TYPE_VEC2;
5212 } else if constexpr (std::is_same_v<T, vec3>) {
5213 globaldata[label].global_data_vec3 = data;
5214 globaldata[label].type = HELIOS_TYPE_VEC3;
5215 } else if constexpr (std::is_same_v<T, vec4>) {
5216 globaldata[label].global_data_vec4 = data;
5217 globaldata[label].type = HELIOS_TYPE_VEC4;
5218 } else if constexpr (std::is_same_v<T, int2>) {
5219 globaldata[label].global_data_int2 = data;
5220 globaldata[label].type = HELIOS_TYPE_INT2;
5221 } else if constexpr (std::is_same_v<T, int3>) {
5222 globaldata[label].global_data_int3 = data;
5223 globaldata[label].type = HELIOS_TYPE_INT3;
5224 } else if constexpr (std::is_same_v<T, int4>) {
5225 globaldata[label].global_data_int4 = data;
5226 globaldata[label].type = HELIOS_TYPE_INT4;
5227 } 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 *>) {
5228 globaldata[label].global_data_string = data;
5229 globaldata[label].type = HELIOS_TYPE_STRING;
5230 } else if constexpr (std::is_same_v<T, bool>) {
5231 globaldata[label].global_data_bool = data;
5232 globaldata[label].type = HELIOS_TYPE_BOOL;
5233 }
5234 globaldata[label].version++;
5235 }
5236
5238
5242 template<typename T>
5243 void getGlobalData(const char *label, T &data) const {
5244 // Use SFINAE to detect if T is std::vector<U> for some U
5245 if constexpr (std::is_same_v<T, std::vector<int>>) {
5246 // Vector case for int
5247 if (globaldata.at(label).type == HELIOS_TYPE_INT) {
5248 data = globaldata.at(label).global_data_int;
5249 } else {
5250 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) + " does not have type int.");
5251 }
5252 } else if constexpr (std::is_same_v<T, std::vector<uint>>) {
5253 // Vector case for uint
5254 if (globaldata.at(label).type == HELIOS_TYPE_UINT) {
5255 data = globaldata.at(label).global_data_uint;
5256 } else {
5257 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) + " does not have type uint.");
5258 }
5259 } else if constexpr (std::is_same_v<T, std::vector<float>>) {
5260 // Vector case for float
5261 if (globaldata.at(label).type == HELIOS_TYPE_FLOAT) {
5262 data = globaldata.at(label).global_data_float;
5263 } else {
5264 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) + " does not have type float.");
5265 }
5266 } else if constexpr (std::is_same_v<T, std::vector<double>>) {
5267 // Vector case for double
5268 if (globaldata.at(label).type == HELIOS_TYPE_DOUBLE) {
5269 data = globaldata.at(label).global_data_double;
5270 } else {
5271 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) + " does not have type double.");
5272 }
5273 } else if constexpr (std::is_same_v<T, std::vector<vec2>>) {
5274 // Vector case for vec2
5275 if (globaldata.at(label).type == HELIOS_TYPE_VEC2) {
5276 data = globaldata.at(label).global_data_vec2;
5277 } else {
5278 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) + " does not have type vec2.");
5279 }
5280 } else if constexpr (std::is_same_v<T, std::vector<vec3>>) {
5281 // Vector case for vec3
5282 if (globaldata.at(label).type == HELIOS_TYPE_VEC3) {
5283 data = globaldata.at(label).global_data_vec3;
5284 } else {
5285 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) + " does not have type vec3.");
5286 }
5287 } else if constexpr (std::is_same_v<T, std::vector<vec4>>) {
5288 // Vector case for vec4
5289 if (globaldata.at(label).type == HELIOS_TYPE_VEC4) {
5290 data = globaldata.at(label).global_data_vec4;
5291 } else {
5292 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) + " does not have type vec4.");
5293 }
5294 } else if constexpr (std::is_same_v<T, std::vector<int2>>) {
5295 // Vector case for int2
5296 if (globaldata.at(label).type == HELIOS_TYPE_INT2) {
5297 data = globaldata.at(label).global_data_int2;
5298 } else {
5299 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) + " does not have type int2.");
5300 }
5301 } else if constexpr (std::is_same_v<T, std::vector<int3>>) {
5302 // Vector case for int3
5303 if (globaldata.at(label).type == HELIOS_TYPE_INT3) {
5304 data = globaldata.at(label).global_data_int3;
5305 } else {
5306 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) + " does not have type int3.");
5307 }
5308 } else if constexpr (std::is_same_v<T, std::vector<int4>>) {
5309 // Vector case for int4
5310 if (globaldata.at(label).type == HELIOS_TYPE_INT4) {
5311 data = globaldata.at(label).global_data_int4;
5312 } else {
5313 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) + " does not have type int4.");
5314 }
5315 } else if constexpr (std::is_same_v<T, std::vector<std::string>>) {
5316 // Vector case for string
5317 if (globaldata.at(label).type == HELIOS_TYPE_STRING) {
5318 data = globaldata.at(label).global_data_string;
5319 } else {
5320 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) + " does not have type string.");
5321 }
5322 } else if constexpr (std::is_same_v<T, int>) {
5323 // Scalar case for int
5324 if (globaldata.at(label).type == HELIOS_TYPE_INT) {
5325 data = globaldata.at(label).global_data_int.front();
5326 } else {
5327 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) + " does not have type int.");
5328 }
5329 } else if constexpr (std::is_same_v<T, uint>) {
5330 // Scalar case for uint
5331 if (globaldata.at(label).type == HELIOS_TYPE_UINT) {
5332 data = globaldata.at(label).global_data_uint.front();
5333 } else {
5334 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) + " does not have type uint.");
5335 }
5336 } else if constexpr (std::is_same_v<T, float>) {
5337 // Scalar case for float
5338 if (globaldata.at(label).type == HELIOS_TYPE_FLOAT) {
5339 data = globaldata.at(label).global_data_float.front();
5340 } else {
5341 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) + " does not have type float.");
5342 }
5343 } else if constexpr (std::is_same_v<T, double>) {
5344 // Scalar case for double
5345 if (globaldata.at(label).type == HELIOS_TYPE_DOUBLE) {
5346 data = globaldata.at(label).global_data_double.front();
5347 } else {
5348 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) + " does not have type double.");
5349 }
5350 } else if constexpr (std::is_same_v<T, vec2>) {
5351 // Scalar case for vec2
5352 if (globaldata.at(label).type == HELIOS_TYPE_VEC2) {
5353 data = globaldata.at(label).global_data_vec2.front();
5354 } else {
5355 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) + " does not have type vec2.");
5356 }
5357 } else if constexpr (std::is_same_v<T, vec3>) {
5358 // Scalar case for vec3
5359 if (globaldata.at(label).type == HELIOS_TYPE_VEC3) {
5360 data = globaldata.at(label).global_data_vec3.front();
5361 } else {
5362 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) + " does not have type vec3.");
5363 }
5364 } else if constexpr (std::is_same_v<T, vec4>) {
5365 // Scalar case for vec4
5366 if (globaldata.at(label).type == HELIOS_TYPE_VEC4) {
5367 data = globaldata.at(label).global_data_vec4.front();
5368 } else {
5369 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) + " does not have type vec4.");
5370 }
5371 } else if constexpr (std::is_same_v<T, int2>) {
5372 // Scalar case for int2
5373 if (globaldata.at(label).type == HELIOS_TYPE_INT2) {
5374 data = globaldata.at(label).global_data_int2.front();
5375 } else {
5376 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) + " does not have type int2.");
5377 }
5378 } else if constexpr (std::is_same_v<T, int3>) {
5379 // Scalar case for int3
5380 if (globaldata.at(label).type == HELIOS_TYPE_INT3) {
5381 data = globaldata.at(label).global_data_int3.front();
5382 } else {
5383 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) + " does not have type int3.");
5384 }
5385 } else if constexpr (std::is_same_v<T, int4>) {
5386 // Scalar case for int4
5387 if (globaldata.at(label).type == HELIOS_TYPE_INT4) {
5388 data = globaldata.at(label).global_data_int4.front();
5389 } else {
5390 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) + " does not have type int4.");
5391 }
5392 } 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 *>) {
5393 // Scalar case for string
5394 if (globaldata.at(label).type == HELIOS_TYPE_STRING) {
5395 data = globaldata.at(label).global_data_string.front();
5396 } else {
5397 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) + " does not have type string.");
5398 }
5399 } else if constexpr (std::is_same_v<T, bool>) {
5400 // Scalar case for bool
5401 if (globaldata.at(label).type == HELIOS_TYPE_BOOL) {
5402 data = globaldata.at(label).global_data_bool.front();
5403 } else {
5404 helios_runtime_error("ERROR (Context::getGlobalData): Attempted to get data for type bool, but data " + std::string(label) + " does not have type bool.");
5405 }
5406 } else {
5407 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> ||
5408 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 *> ||
5409 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>> ||
5410 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>> ||
5411 std::is_same_v<T, std::vector<std::string>> || std::is_same_v<T, std::vector<bool>>,
5412 "CompoundObject::getGlobalData() was called with an unsupported type.");
5413 }
5414 }
5415
5417
5421 void renameGlobalData(const char *old_label, const char *new_label);
5422
5424
5428 void duplicateGlobalData(const char *old_label, const char *new_label);
5429
5431
5434 void clearGlobalData(const char *label);
5435
5437
5441 HeliosDataType getGlobalDataType(const char *label) const;
5442
5444
5448 size_t getGlobalDataSize(const char *label) const;
5449
5451
5456 uint64_t getGlobalDataVersion(const char *label) const;
5457
5459
5462 [[nodiscard]] std::vector<std::string> listGlobalData() const;
5463
5465
5469 bool doesGlobalDataExist(const char *label) const;
5470
5472
5477 void incrementGlobalData(const char *label, int increment);
5478
5480
5485 void incrementGlobalData(const char *label, uint increment);
5486
5488
5493 void incrementGlobalData(const char *label, float increment);
5494
5496
5501 void incrementGlobalData(const char *label, double increment);
5502
5503 //--------- Compound Objects Methods -------------//
5504
5506
5509 [[nodiscard]] uint getObjectCount() const;
5510
5512
5515 [[nodiscard]] bool doesObjectExist(uint ObjID) const;
5516
5518
5521 [[nodiscard]] std::vector<uint> getAllObjectIDs() const;
5522
5524
5527 void deleteObject(uint ObjID);
5528
5530
5533 void deleteObject(const std::vector<uint> &ObjIDs);
5534
5536
5540 uint copyObject(uint ObjID);
5541
5543
5547 std::vector<uint> copyObject(const std::vector<uint> &ObjIDs);
5548
5550
5554 void copyObjectData(uint source_objID, uint destination_objID);
5555
5557
5562 void duplicateObjectData(uint objID, const char *old_label, const char *new_label);
5563
5565
5570 void renameObjectData(uint objID, const char *old_label, const char *new_label);
5571
5573
5579 std::vector<uint> filterObjectsByData(const std::vector<uint> &ObjIDs, const char *object_data, float threshold, const char *comparator) const;
5580
5582
5586 void translateObject(uint ObjID, const vec3 &shift) const;
5587
5589
5593 void translateObject(const std::vector<uint> &ObjIDs, const vec3 &shift) const;
5594
5596
5601 void rotateObject(uint ObjID, float rotation_radians, const char *rotation_axis_xyz) const;
5602
5604
5609 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const char *rotation_axis_xyz) const;
5610
5612
5617 void rotateObject(uint ObjID, float rotation_radians, const vec3 &rotation_axis_vector) const;
5618
5620
5625 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_axis_vector) const;
5626
5628
5634 void rotateObject(uint ObjID, float rotation_radians, const vec3 &rotation_origin, const vec3 &rotation_axis_vector) const;
5635
5637
5643 void rotateObject(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_origin, const vec3 &rotation_axis_vector) const;
5644
5646
5651 void rotateObjectAboutOrigin(uint ObjID, float rotation_radians, const vec3 &rotation_axis_vector) const;
5652
5654
5659 void rotateObjectAboutOrigin(const std::vector<uint> &ObjIDs, float rotation_radians, const vec3 &rotation_axis_vector) const;
5660
5662
5666 void scaleObject(uint ObjID, const helios::vec3 &scalefact) const;
5667
5669
5673 void scaleObject(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
5674
5676
5680 void scaleObjectAboutCenter(uint ObjID, const helios::vec3 &scalefact) const;
5681
5683
5687 void scaleObjectAboutCenter(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
5688
5690
5695 void scaleObjectAboutPoint(uint ObjID, const helios::vec3 &scalefact, const helios::vec3 &point) const;
5696
5698
5703 void scaleObjectAboutPoint(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact, const helios::vec3 &point) const;
5704
5706
5711 void scaleObjectAboutOrigin(uint ObjID, const helios::vec3 &scalefact) const;
5712
5714
5719 void scaleObjectAboutOrigin(const std::vector<uint> &ObjIDs, const helios::vec3 &scalefact) const;
5720
5722
5725 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(uint ObjID) const;
5726
5728
5731 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(const std::vector<uint> &ObjIDs) const;
5732
5734
5737 [[nodiscard]] std::vector<uint> getObjectPrimitiveUUIDs(const std::vector<std::vector<uint>> &ObjIDs) const;
5738
5740
5743 [[nodiscard]] helios::ObjectType getObjectType(uint ObjID) const;
5744
5746
5749 [[nodiscard]] float getTileObjectAreaRatio(uint ObjID) const;
5750
5752
5755 [[nodiscard]] std::vector<float> getTileObjectAreaRatio(const std::vector<uint> &ObjIDs) const;
5756
5758
5762 void setTileObjectSubdivisionCount(const std::vector<uint> &ObjIDs, const int2 &new_subdiv);
5763
5765
5769 void setTileObjectSubdivisionCount(const std::vector<uint> &ObjIDs, float area_ratio);
5770
5772
5777 [[nodiscard]] helios::vec3 getTileObjectCenter(uint ObjID) const;
5778
5780
5783 [[nodiscard]] helios::vec2 getTileObjectSize(uint ObjID) const;
5784
5786
5789 [[nodiscard]] helios::int2 getTileObjectSubdivisionCount(uint ObjID) const;
5790
5792
5795 [[nodiscard]] helios::vec3 getTileObjectNormal(uint ObjID) const;
5796
5798
5801 [[nodiscard]] std::vector<helios::vec2> getTileObjectTextureUV(uint ObjID) const;
5802
5804
5807 [[nodiscard]] std::vector<helios::vec3> getTileObjectVertices(uint ObjID) const;
5808
5810
5813 [[nodiscard]] helios::vec3 getSphereObjectCenter(uint ObjID) const;
5814
5816
5819 [[nodiscard]] helios::vec3 getSphereObjectRadius(uint ObjID) const;
5820
5822
5825 [[nodiscard]] uint getSphereObjectSubdivisionCount(uint ObjID) const;
5826
5828
5831 [[nodiscard]] float getSphereObjectVolume(uint ObjID) const;
5832
5834
5837 [[nodiscard]] uint getTubeObjectSubdivisionCount(uint ObjID) const;
5838
5840
5843 [[nodiscard]] std::vector<helios::vec3> getTubeObjectNodes(uint ObjID) const;
5844
5846
5849 [[nodiscard]] uint getTubeObjectNodeCount(uint ObjID) const;
5850
5852
5855 [[nodiscard]] std::vector<float> getTubeObjectNodeRadii(uint ObjID) const;
5856
5858
5861 [[nodiscard]] std::vector<RGBcolor> getTubeObjectNodeColors(uint ObjID) const;
5862
5864
5867 [[nodiscard]] float getTubeObjectVolume(uint ObjID) const;
5868
5870
5874 [[nodiscard]] float getTubeObjectSegmentVolume(uint ObjID, uint segment_index) const;
5875
5877
5883 void appendTubeSegment(uint ObjID, const helios::vec3 &node_position, float radius, const RGBcolor &color);
5884
5886
5893 void appendTubeSegment(uint ObjID, const helios::vec3 &node_position, float node_radius, const char *texturefile, const helios::vec2 &textureuv_ufrac);
5894
5896
5900 void scaleTubeGirth(uint ObjID, float scale_factor);
5901
5903
5907 void setTubeRadii(uint ObjID, const std::vector<float> &node_radii);
5908
5910
5914 void scaleTubeLength(uint ObjID, float scale_factor);
5915
5917
5921 void pruneTubeNodes(uint ObjID, uint node_index);
5922
5924
5928 void setTubeNodes(uint ObjID, const std::vector<helios::vec3> &node_xyz);
5929
5931
5934 [[nodiscard]] helios::vec3 getBoxObjectCenter(uint ObjID) const;
5935
5937
5940 [[nodiscard]] helios::vec3 getBoxObjectSize(uint ObjID) const;
5941
5943
5946 [[nodiscard]] helios::int3 getBoxObjectSubdivisionCount(uint ObjID) const;
5947
5949
5952 [[nodiscard]] float getBoxObjectVolume(uint ObjID) const;
5953
5955
5958 [[nodiscard]] helios::vec3 getDiskObjectCenter(uint ObjID) const;
5959
5961
5964 [[nodiscard]] helios::vec2 getDiskObjectSize(uint ObjID) const;
5965
5967
5970 [[nodiscard]] uint getDiskObjectSubdivisionCount(uint ObjID) const;
5971
5973
5976 [[nodiscard]] float getPolymeshObjectVolume(uint ObjID) const;
5977
5979
5982 [[nodiscard]] uint getConeObjectSubdivisionCount(uint ObjID) const;
5983
5985
5988 [[nodiscard]] std::vector<helios::vec3> getConeObjectNodes(uint ObjID) const;
5989
5991
5994 [[nodiscard]] std::vector<float> getConeObjectNodeRadii(uint ObjID) const;
5995
5997
6001 [[nodiscard]] helios::vec3 getConeObjectNode(uint ObjID, int number) const;
6002
6004
6008 [[nodiscard]] float getConeObjectNodeRadius(uint ObjID, int number) const;
6009
6011
6014 [[nodiscard]] helios::vec3 getConeObjectAxisUnitVector(uint ObjID) const;
6015
6017
6021 [[nodiscard]] float getConeObjectLength(uint ObjID) const;
6022
6024
6027 [[nodiscard]] float getConeObjectVolume(uint ObjID) const;
6028
6030
6034 void scaleConeObjectLength(uint ObjID, float scale_factor);
6035
6037
6041 void scaleConeObjectGirth(uint ObjID, float scale_factor);
6042
6044
6053 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv);
6054
6056
6065 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const RGBcolor &color);
6066
6068
6077 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile);
6078
6080
6090 uint addTileObject(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile, const int2 &texture_repeat);
6091
6093
6101 uint addSphereObject(uint Ndivs, const vec3 &center, float radius);
6102
6104
6112 uint addSphereObject(uint Ndivs, const vec3 &center, float radius, const RGBcolor &color);
6113
6115
6123 uint addSphereObject(uint Ndivs, const vec3 &center, float radius, const char *texturefile);
6124
6126
6134 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius);
6135
6137
6145 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius, const RGBcolor &color);
6146
6148
6156 uint addSphereObject(uint Ndivs, const vec3 &center, const vec3 &radius, const char *texturefile);
6157
6159
6168 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius);
6169
6171
6180 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const std::vector<RGBcolor> &color);
6181
6183
6193 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile);
6194
6196
6207 uint addTubeObject(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile, const std::vector<float> &textureuv_ufrac);
6208
6210
6219 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv);
6220
6222
6231 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color);
6232
6234
6243 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile);
6244
6246
6256 uint addBoxObject(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color, bool reverse_normals);
6257
6259
6269 uint addBoxObject(vec3 center, const vec3 &size, const int3 &subdiv, const char *texturefile, bool reverse_normals);
6270
6272
6281 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size);
6282
6284
6293 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
6294
6296
6305 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6306
6308
6317 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6318
6320
6330 uint addDiskObject(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
6331
6333
6342 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6343
6345
6354 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6355
6357
6367 uint addDiskObject(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texturefile);
6368
6370
6375 uint addPolymeshObject(const std::vector<uint> &UUIDs);
6376
6378
6389 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1);
6390
6392
6403 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const RGBcolor &color);
6404
6406
6417 uint addConeObject(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const char *texturefile);
6418
6420
6428 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius);
6429
6431
6439 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius, const RGBcolor &color);
6440
6442
6450 std::vector<uint> addSphere(uint Ndivs, const vec3 &center, float radius, const char *texturefile);
6451
6453
6462 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv);
6463
6465
6474 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const RGBcolor &color);
6475
6477
6486 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile);
6487
6489
6499 std::vector<uint> addTile(const vec3 &center, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char *texturefile, const int2 &texture_repeat);
6500
6502
6511 std::vector<uint> addTube(uint Ndivs, const std::vector<vec3> &nodes, const std::vector<float> &radius);
6512
6514
6523 std::vector<uint> addTube(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const std::vector<RGBcolor> &color);
6524
6526
6535 std::vector<uint> addTube(uint radial_subdivisions, const std::vector<vec3> &nodes, const std::vector<float> &radius, const char *texturefile);
6536
6538
6547 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv);
6548
6550
6559 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color);
6560
6562
6571 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile);
6572
6574
6584 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const RGBcolor &color, bool reverse_normals);
6585
6587
6597 std::vector<uint> addBox(const vec3 &center, const vec3 &size, const int3 &subdiv, const char *texturefile, bool reverse_normals);
6598
6600
6609 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size);
6610
6612
6621 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation);
6622
6624
6633 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6634
6636
6645 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6646
6648
6658 std::vector<uint> addDisk(uint Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texture_file);
6659
6661
6670 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBcolor &color);
6671
6673
6682 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::RGBAcolor &color);
6683
6685
6695 std::vector<uint> addDisk(const int2 &Ndivs, const helios::vec3 &center, const helios::vec2 &size, const helios::SphericalCoord &rotation, const char *texturefile);
6696
6698
6708 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1);
6709
6711
6721 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, RGBcolor &color);
6722
6724
6734 std::vector<uint> addCone(uint Ndivs, const vec3 &node0, const vec3 &node1, float radius0, float radius1, const char *texturefile);
6735
6737
6744 void addTimeseriesData(const char *label, float value, const Date &date, const Time &time);
6745
6747
6752 void setCurrentTimeseriesPoint(const char *label, uint index);
6753
6755
6762 float queryTimeseriesData(const char *label, const Date &date, const Time &time) const;
6763
6765
6770 float queryTimeseriesData(const char *label) const;
6771
6773
6779 float queryTimeseriesData(const char *label, uint index) const;
6780
6782
6788 Time queryTimeseriesTime(const char *label, uint index) const;
6789
6791
6797 Date queryTimeseriesDate(const char *label, uint index) const;
6798
6800
6804 uint getTimeseriesLength(const char *label) const;
6805
6807
6811 bool doesTimeseriesVariableExist(const char *label) const;
6812
6814 [[nodiscard]] std::vector<std::string> listTimeseriesVariables() const;
6815
6817
6824 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);
6825
6827
6832 void getDomainBoundingBox(helios::vec2 &xbounds, helios::vec2 &ybounds, helios::vec2 &zbounds) const;
6833
6835
6841 void getDomainBoundingBox(const std::vector<uint> &UUIDs, helios::vec2 &xbounds, helios::vec2 &ybounds, helios::vec2 &zbounds) const;
6842
6844
6848 void getDomainBoundingSphere(helios::vec3 &center, float &radius) const;
6849
6851
6856 void getDomainBoundingSphere(const std::vector<uint> &UUIDs, helios::vec3 &center, float &radius) const;
6857
6859
6862 void cropDomainX(const vec2 &xbounds);
6863
6865
6868 void cropDomainY(const vec2 &ybounds);
6869
6871
6874 void cropDomainZ(const vec2 &zbounds);
6875
6877
6883 void cropDomain(std::vector<uint> &UUIDs, const vec2 &xbounds, const vec2 &ybounds, const vec2 &zbounds);
6884
6886
6891 void cropDomain(const vec2 &xbounds, const vec2 &ybounds, const vec2 &zbounds);
6892
6894
6900 void colorPrimitiveByDataPseudocolor(const std::vector<uint> &UUIDs, const std::string &primitive_data, const std::string &colormap, uint Ncolors);
6901
6903
6911 void colorPrimitiveByDataPseudocolor(const std::vector<uint> &UUIDs, const std::string &primitive_data, const std::string &colormap, uint Ncolors, float data_min, float data_max);
6912
6914
6920 std::vector<uint> loadXML(const char *filename, bool quiet = false);
6921
6923
6926 [[nodiscard]] std::vector<std::string> getLoadedXMLFiles();
6927
6929
6935 static bool scanXMLForTag(const std::string &filename, const std::string &tag, const std::string &label = "");
6936
6938
6942 void writeXML(const char *filename, bool quiet = false) const;
6943
6945
6950 void writeXML(const char *filename, const std::vector<uint> &UUIDs, bool quiet = false) const;
6951
6953
6958 void writeXML_byobject(const char *filename, const std::vector<uint> &UUIDs, bool quiet = false) const;
6959
6961
6966 void writePrimitiveData(const std::string &filename, const std::vector<std::string> &column_format, bool print_header = false) const;
6967
6969
6975 void writePrimitiveData(const std::string &filename, const std::vector<std::string> &column_format, const std::vector<uint> &UUIDs, bool print_header = false) const;
6976
6978
6984 std::vector<uint> loadPLY(const char *filename, bool silent = false);
6985
6987
6996 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const std::string &upaxis = "YUP", bool silent = false);
6997
6999
7009 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const std::string &upaxis = "YUP", bool silent = false);
7010
7012
7021 std::vector<uint> loadPLY(const char *filename, const vec3 &origin, float height, const RGBcolor &default_color, const std::string &upaxis = "YUP", bool silent = false);
7022
7024
7034 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);
7035
7037
7040 void writePLY(const char *filename) const;
7041
7043
7047 void writePLY(const char *filename, const std::vector<uint> &UUIDs) const;
7048
7049 // Asset directory registration removed - now using HELIOS_BUILD resolution
7050
7052
7056 std::vector<uint> loadOBJ(const char *filename, bool silent = false);
7057
7059
7068 std::vector<uint> loadOBJ(const char *filename, const vec3 &origin, float height, const SphericalCoord &rotation, const RGBcolor &default_color, bool silent = false);
7069
7071
7081 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);
7082
7083
7085
7095 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);
7096
7098
7103 void writeOBJ(const std::string &filename, bool write_normals = false, bool silent = false) const;
7104
7106
7112 void writeOBJ(const std::string &filename, const std::vector<uint> &UUIDs, bool write_normals = false, bool silent = false) const;
7113
7115
7122 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;
7123
7124 //------------ FILE PATH RESOLUTION ----------------//
7125
7127
7132 std::filesystem::path resolveFilePath(const std::string &filename) const;
7133
7135
7141 void setDate(int day, int month, int year);
7142
7144
7148 void setDate(const Date &date);
7149
7151
7156 void setDate(int Julian_day, int year);
7157
7159
7163 [[nodiscard]] helios::Date getDate() const;
7164
7166
7170 [[nodiscard]] const char *getMonthString() const;
7171
7173
7177 [[nodiscard]] int getJulianDate() const;
7178
7180
7186 void setTime(int minute, int hour);
7187
7189
7196 void setTime(int second, int minute, int hour);
7197
7199
7204 void setTime(const Time &time);
7205
7207
7211 [[nodiscard]] helios::Time getTime() const;
7212
7214
7217 void setLocation(const helios::Location &location);
7218
7220
7223 [[nodiscard]] helios::Location getLocation() const;
7224
7226
7229 float randu();
7230
7232
7237 float randu(float min, float max);
7238
7240
7245 int randu(int min, int max);
7246
7248
7251 float randn();
7252
7254
7259 float randn(float mean, float stddev);
7260
7262
7266 void duplicatePrimitiveData(const char *existing_data_label, const char *copy_data_label);
7267
7269
7274 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, float &mean) const;
7275
7277
7282 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, double &mean) const;
7283
7285
7290 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &mean) const;
7291
7293
7298 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &mean) const;
7299
7301
7306 void calculatePrimitiveDataMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &mean) const;
7307
7309
7314 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, float &awt_mean) const;
7315
7317
7322 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, double &awt_mean) const;
7323
7325
7330 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &awt_mean) const;
7331
7333
7338 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &awt_mean) const;
7339
7341
7346 void calculatePrimitiveDataAreaWeightedMean(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &awt_mean) const;
7347
7349
7354 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, float &sum) const;
7355
7357
7362 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, double &sum) const;
7363
7365
7370 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &sum) const;
7371
7373
7378 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &sum) const;
7379
7381
7386 void calculatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &sum) const;
7387
7389
7394 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, float &awt_sum) const;
7395
7397
7402 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, double &sum) const;
7403
7405
7410 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec2 &sum) const;
7411
7413
7418 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec3 &sum) const;
7419
7421
7426 void calculatePrimitiveDataAreaWeightedSum(const std::vector<uint> &UUIDs, const std::string &label, helios::vec4 &sum) const;
7427
7429
7435 void scalePrimitiveData(const std::vector<uint> &UUIDs, const std::string &label, float scaling_factor);
7436
7438
7443 void scalePrimitiveData(const std::string &label, float scaling_factor);
7444
7446
7452 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, int increment);
7453
7455
7461 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, uint increment);
7462
7464
7470 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, float increment);
7471
7473
7479 void incrementPrimitiveData(const std::vector<uint> &UUIDs, const char *label, double increment);
7480
7482
7488 void aggregatePrimitiveDataSum(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label);
7489
7491
7497 void aggregatePrimitiveDataProduct(const std::vector<uint> &UUIDs, const std::vector<std::string> &primitive_data_labels, const std::string &result_primitive_data_label);
7498
7500
7504 [[nodiscard]] float sumPrimitiveSurfaceArea(const std::vector<uint> &UUIDs) const;
7505
7507
7515 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, float filter_value, const std::string &comparator) const;
7516
7518
7526 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, double filter_value, const std::string &comparator) const;
7527
7529
7537 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, int filter_value, const std::string &comparator) const;
7538
7540
7548 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, uint filter_value, const std::string &comparator) const;
7549
7551
7558 [[nodiscard]] std::vector<uint> filterPrimitivesByData(const std::vector<uint> &UUIDs, const std::string &primitive_data_label, const std::string &filter_value) const;
7559
7561
7569 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, float filter_value, const std::string &comparator) const;
7570
7572
7580 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, double filter_value, const std::string &comparator) const;
7581
7583
7591 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, int filter_value, const std::string &comparator) const;
7592
7594
7602 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, uint filter_value, const std::string &comparator) const;
7603
7605
7612 [[nodiscard]] std::vector<uint> filterObjectsByData(const std::vector<uint> &objIDs, const std::string &object_data_label, const std::string &filter_value) const;
7613
7615
7625 std::vector<std::string> generateTexturesFromColormap(const std::string &texturefile, const std::vector<RGBcolor> &colormap_data);
7626
7628
7633 std::vector<RGBcolor> generateColormap(const std::string &colormap, uint Ncolors);
7634
7636
7643 std::vector<RGBcolor> generateColormap(const std::vector<helios::RGBcolor> &ctable, const std::vector<float> &cfrac, uint Ncolors);
7644
7645 // ---------- Template method implementations for data type consistency ---------- //
7646
7647 template<typename T>
7648 void storeDataWithTypeCasting(uint UUID, const char *label, const T &data, HeliosDataType target_type) {
7649 // Only cast between numeric scalar types
7650 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>) {
7651 if (target_type == HELIOS_TYPE_INT) {
7652 primitives.at(UUID)->setPrimitiveData(label, static_cast<int>(data));
7653 } else if (target_type == HELIOS_TYPE_UINT) {
7654 primitives.at(UUID)->setPrimitiveData(label, static_cast<uint>(data));
7655 } else if (target_type == HELIOS_TYPE_FLOAT) {
7656 primitives.at(UUID)->setPrimitiveData(label, static_cast<float>(data));
7657 } else if (target_type == HELIOS_TYPE_DOUBLE) {
7658 primitives.at(UUID)->setPrimitiveData(label, static_cast<double>(data));
7659 } else {
7660 // Fallback: store as original type
7661 primitives.at(UUID)->setPrimitiveData(label, data);
7662 }
7663 } else {
7664 // For non-numeric types, store as-is
7665 primitives.at(UUID)->setPrimitiveData(label, data);
7666 }
7667 }
7668
7669 template<typename T>
7670 void storeObjectDataWithTypeCasting(uint objID, const char *label, const T &data, HeliosDataType target_type) {
7671 // Only cast between numeric scalar types
7672 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>) {
7673 if (target_type == HELIOS_TYPE_INT) {
7674 objects.at(objID)->setObjectData(label, static_cast<int>(data));
7675 } else if (target_type == HELIOS_TYPE_UINT) {
7676 objects.at(objID)->setObjectData(label, static_cast<uint>(data));
7677 } else if (target_type == HELIOS_TYPE_FLOAT) {
7678 objects.at(objID)->setObjectData(label, static_cast<float>(data));
7679 } else if (target_type == HELIOS_TYPE_DOUBLE) {
7680 objects.at(objID)->setObjectData(label, static_cast<double>(data));
7681 } else {
7682 // Fallback: store as original type
7683 objects.at(objID)->setObjectData(label, data);
7684 }
7685 } else {
7686 // For non-numeric types, store as-is
7687 objects.at(objID)->setObjectData(label, data);
7688 }
7689 }
7690
7691 template<typename T>
7692 HeliosDataType registerOrValidatePrimitiveDataType(const std::string &label, HeliosDataType data_type) {
7693 auto it = primitive_data_type_registry.find(label);
7694 if (it == primitive_data_type_registry.end()) {
7695 // First time this label is used - register the type
7696 primitive_data_type_registry[label] = data_type;
7697 return data_type;
7698 } else {
7699 // Label exists - check for type consistency
7700 HeliosDataType expected_type = it->second;
7701 if (expected_type != data_type) {
7702 // Types don't match - check if casting is possible
7703 if (!isTypeCastingSupported(data_type, expected_type)) {
7704 helios_runtime_error("ERROR (Context::registerOrValidatePrimitiveDataType): Data type mismatch for label '" + label + "'. Expected " + dataTypeToString(expected_type) + " but got " + dataTypeToString(data_type) +
7705 ". Type casting between these types is not supported.");
7706 } else {
7707 std::cerr << "WARNING (Context::registerOrValidatePrimitiveDataType): Type casting from " + dataTypeToString(data_type) + " to " + dataTypeToString(expected_type) + " for label '" + label +
7708 "'. Consider using consistent types."
7709 << std::endl;
7710 }
7711 }
7712 return expected_type;
7713 }
7714 }
7715
7716 template<typename T>
7717 HeliosDataType registerOrValidateObjectDataType(const std::string &label, HeliosDataType data_type) {
7718 auto it = object_data_type_registry.find(label);
7719 if (it == object_data_type_registry.end()) {
7720 // First time this label is used - register the type
7721 object_data_type_registry[label] = data_type;
7722 return data_type;
7723 } else {
7724 // Label exists - check for type consistency
7725 HeliosDataType expected_type = it->second;
7726 if (expected_type != data_type) {
7727 // Types don't match - check if casting is possible
7728 if (!isTypeCastingSupported(data_type, expected_type)) {
7729 helios_runtime_error("ERROR (Context::registerOrValidateObjectDataType): Data type mismatch for label '" + label + "'. Expected " + dataTypeToString(expected_type) + " but got " + dataTypeToString(data_type) +
7730 ". Type casting between these types is not supported.");
7731 } else {
7732 std::cerr << "WARNING (Context::registerOrValidateObjectDataType): Type casting from " + dataTypeToString(data_type) + " to " + dataTypeToString(expected_type) + " for label '" + label + "'. Consider using consistent types."
7733 << std::endl;
7734 }
7735 }
7736 return expected_type;
7737 }
7738 }
7739
7740 //----------- TEMPLATE METHOD IMPLEMENTATIONS FOR VALUE REGISTRY ----------//
7741
7743 template<typename T>
7744 void incrementPrimitiveValueRegistry(const std::string &label, const T &value) {
7745 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 *>) {
7746 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7747 primitive_string_value_registry[label][string_value]++;
7748 } else if constexpr (std::is_same_v<T, int>) {
7749 primitive_int_value_registry[label][value]++;
7750 } else if constexpr (std::is_same_v<T, uint>) {
7751 primitive_uint_value_registry[label][value]++;
7752 }
7753 }
7754
7756 template<typename T>
7757 void decrementPrimitiveValueRegistry(const std::string &label, const T &value) {
7758 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 *>) {
7759 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7760 auto label_it = primitive_string_value_registry.find(label);
7761 if (label_it != primitive_string_value_registry.end()) {
7762 auto value_it = label_it->second.find(string_value);
7763 if (value_it != label_it->second.end() && value_it->second > 0) {
7764 value_it->second--;
7765 if (value_it->second == 0) {
7766 label_it->second.erase(value_it);
7767 if (label_it->second.empty()) {
7768 primitive_string_value_registry.erase(label_it);
7769 }
7770 }
7771 }
7772 }
7773 } else if constexpr (std::is_same_v<T, int>) {
7774 auto label_it = primitive_int_value_registry.find(label);
7775 if (label_it != primitive_int_value_registry.end()) {
7776 auto value_it = label_it->second.find(value);
7777 if (value_it != label_it->second.end() && value_it->second > 0) {
7778 value_it->second--;
7779 if (value_it->second == 0) {
7780 label_it->second.erase(value_it);
7781 if (label_it->second.empty()) {
7782 primitive_int_value_registry.erase(label_it);
7783 }
7784 }
7785 }
7786 }
7787 } else if constexpr (std::is_same_v<T, uint>) {
7788 auto label_it = primitive_uint_value_registry.find(label);
7789 if (label_it != primitive_uint_value_registry.end()) {
7790 auto value_it = label_it->second.find(value);
7791 if (value_it != label_it->second.end() && value_it->second > 0) {
7792 value_it->second--;
7793 if (value_it->second == 0) {
7794 label_it->second.erase(value_it);
7795 if (label_it->second.empty()) {
7796 primitive_uint_value_registry.erase(label_it);
7797 }
7798 }
7799 }
7800 }
7801 }
7802 }
7803
7805 template<typename T>
7806 void incrementObjectValueRegistry(const std::string &label, const T &value) {
7807 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 *>) {
7808 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7809 object_string_value_registry[label][string_value]++;
7810 } else if constexpr (std::is_same_v<T, int>) {
7811 object_int_value_registry[label][value]++;
7812 } else if constexpr (std::is_same_v<T, uint>) {
7813 object_uint_value_registry[label][value]++;
7814 }
7815 }
7816
7818 template<typename T>
7819 void decrementObjectValueRegistry(const std::string &label, const T &value) {
7820 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 *>) {
7821 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7822 auto label_it = object_string_value_registry.find(label);
7823 if (label_it != object_string_value_registry.end()) {
7824 auto value_it = label_it->second.find(string_value);
7825 if (value_it != label_it->second.end() && value_it->second > 0) {
7826 value_it->second--;
7827 if (value_it->second == 0) {
7828 label_it->second.erase(value_it);
7829 if (label_it->second.empty()) {
7830 object_string_value_registry.erase(label_it);
7831 }
7832 }
7833 }
7834 }
7835 } else if constexpr (std::is_same_v<T, int>) {
7836 auto label_it = object_int_value_registry.find(label);
7837 if (label_it != object_int_value_registry.end()) {
7838 auto value_it = label_it->second.find(value);
7839 if (value_it != label_it->second.end() && value_it->second > 0) {
7840 value_it->second--;
7841 if (value_it->second == 0) {
7842 label_it->second.erase(value_it);
7843 if (label_it->second.empty()) {
7844 object_int_value_registry.erase(label_it);
7845 }
7846 }
7847 }
7848 }
7849 } else if constexpr (std::is_same_v<T, uint>) {
7850 auto label_it = object_uint_value_registry.find(label);
7851 if (label_it != object_uint_value_registry.end()) {
7852 auto value_it = label_it->second.find(value);
7853 if (value_it != label_it->second.end() && value_it->second > 0) {
7854 value_it->second--;
7855 if (value_it->second == 0) {
7856 label_it->second.erase(value_it);
7857 if (label_it->second.empty()) {
7858 object_uint_value_registry.erase(label_it);
7859 }
7860 }
7861 }
7862 }
7863 }
7864 }
7865
7866 //----------- UNIQUE VALUE QUERY METHODS ----------//
7867
7869
7875 template<typename T>
7876 void getUniquePrimitiveDataValues(const std::string &label, std::vector<T> &values) const {
7877 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.");
7878
7880 helios_runtime_error("ERROR (Context::getUniquePrimitiveDataValues): Value-level caching is not enabled for primitive data label '" + label + "'. Use enablePrimitiveDataValueCaching() first.");
7881 }
7882
7883 values.clear();
7884
7885 if constexpr (std::is_same_v<T, std::string>) {
7886 auto it = primitive_string_value_registry.find(label);
7887 if (it != primitive_string_value_registry.end()) {
7888 values.reserve(it->second.size());
7889 for (const auto &[value, count]: it->second) {
7890 if (count > 0) {
7891 values.push_back(value);
7892 }
7893 }
7894 }
7895 } else if constexpr (std::is_same_v<T, int>) {
7896 auto it = primitive_int_value_registry.find(label);
7897 if (it != primitive_int_value_registry.end()) {
7898 values.reserve(it->second.size());
7899 for (const auto &[value, count]: it->second) {
7900 if (count > 0) {
7901 values.push_back(value);
7902 }
7903 }
7904 }
7905 } else if constexpr (std::is_same_v<T, uint>) {
7906 auto it = primitive_uint_value_registry.find(label);
7907 if (it != primitive_uint_value_registry.end()) {
7908 values.reserve(it->second.size());
7909 for (const auto &[value, count]: it->second) {
7910 if (count > 0) {
7911 values.push_back(value);
7912 }
7913 }
7914 }
7915 }
7916 }
7917
7919
7925 template<typename T>
7926 void getUniqueObjectDataValues(const std::string &label, std::vector<T> &values) const {
7927 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.");
7928
7929 if (!isObjectDataValueCachingEnabled(label)) {
7930 helios_runtime_error("ERROR (Context::getUniqueObjectDataValues): Value-level caching is not enabled for object data label '" + label + "'. Use enableObjectDataValueCaching() first.");
7931 }
7932
7933 values.clear();
7934
7935 if constexpr (std::is_same_v<T, std::string>) {
7936 auto it = object_string_value_registry.find(label);
7937 if (it != object_string_value_registry.end()) {
7938 values.reserve(it->second.size());
7939 for (const auto &[value, count]: it->second) {
7940 if (count > 0) {
7941 values.push_back(value);
7942 }
7943 }
7944 }
7945 } else if constexpr (std::is_same_v<T, int>) {
7946 auto it = object_int_value_registry.find(label);
7947 if (it != object_int_value_registry.end()) {
7948 values.reserve(it->second.size());
7949 for (const auto &[value, count]: it->second) {
7950 if (count > 0) {
7951 values.push_back(value);
7952 }
7953 }
7954 }
7955 } else if constexpr (std::is_same_v<T, uint>) {
7956 auto it = object_uint_value_registry.find(label);
7957 if (it != object_uint_value_registry.end()) {
7958 values.reserve(it->second.size());
7959 for (const auto &[value, count]: it->second) {
7960 if (count > 0) {
7961 values.push_back(value);
7962 }
7963 }
7964 }
7965 }
7966 }
7967 };
7968
7969} // namespace helios
7970
7971
7972#endif