2483 friend class Primitive;
2493 [[nodiscard]] Primitive *getPrimitivePointer_private(
uint UUID)
const;
2500 [[nodiscard]] Patch *getPatchPointer_private(
uint UUID)
const;
2508 [[nodiscard]] Triangle *getTrianglePointer_private(
uint UUID)
const;
2515 [[nodiscard]] Voxel *getVoxelPointer_private(
uint UUID)
const;
2529 [[nodiscard]]
Tile *getTileObjectPointer_private(
uint ObjID)
const;
2536 [[nodiscard]]
Sphere *getSphereObjectPointer_private(
uint ObjID)
const;
2543 [[nodiscard]]
Tube *getTubeObjectPointer_private(
uint ObjID)
const;
2550 [[nodiscard]]
Box *getBoxObjectPointer_private(
uint ObjID)
const;
2557 [[nodiscard]]
Disk *getDiskObjectPointer_private(
uint ObjID)
const;
2564 [[nodiscard]]
Polymesh *getPolymeshObjectPointer_private(
uint ObjID)
const;
2571 [[nodiscard]]
Cone *getConeObjectPointer_private(
uint ObjID)
const;
2574 void invalidateAllUUIDsCache()
const {
2575 all_uuids_cache_valid =
false;
2582 std::unordered_map<uint, Primitive *> primitives;
2585 mutable std::vector<uint> cached_all_uuids;
2587 mutable bool all_uuids_cache_valid =
false;
2593 std::vector<uint> dirty_deleted_primitives;
2596 std::unordered_map<uint, CompoundObject *> objects;
2599 std::map<std::string, std::vector<float>> timeseries_data;
2603 std::map<std::string, std::vector<double>> timeseries_datevalue;
2607 std::map<std::string, Texture> textures;
2609 void addTexture(
const char *texture_file);
2612 bool doesTextureFileExist(
const char *texture_file)
const;
2614 bool validateTextureFileExtenstion(
const char *texture_file)
const;
2619 static constexpr const char *DEFAULT_MATERIAL_LABEL =
"__default__";
2622 std::map<uint, Material> materials;
2625 std::map<std::string, uint> material_label_to_id;
2628 uint currentMaterialID;
2638 uint addMaterial_internal(
const std::string &label,
const RGBAcolor &color,
const std::string &texture =
"");
2641 std::string generateMaterialLabel(
const RGBAcolor &color,
const std::string &texture,
bool texture_override)
const;
2644 bool isMaterialShared(
uint materialID)
const;
2647 uint copyMaterialForPrimitive(
uint primitiveUUID);
2651 std::map<std::string, GlobalData> globaldata;
2653 std::unordered_map<std::string, size_t> primitive_data_label_counts;
2654 std::unordered_map<std::string, size_t> object_data_label_counts;
2659 std::unordered_map<std::string, HeliosDataType> primitive_data_type_registry;
2662 std::unordered_map<std::string, HeliosDataType> object_data_type_registry;
2667 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> primitive_string_value_registry;
2668 std::unordered_map<std::string, std::unordered_map<int, size_t>> primitive_int_value_registry;
2669 std::unordered_map<std::string, std::unordered_map<uint, size_t>> primitive_uint_value_registry;
2672 std::unordered_map<std::string, std::unordered_map<std::string, size_t>> object_string_value_registry;
2673 std::unordered_map<std::string, std::unordered_map<int, size_t>> object_int_value_registry;
2674 std::unordered_map<std::string, std::unordered_map<uint, size_t>> object_uint_value_registry;
2677 std::unordered_set<std::string> cached_primitive_data_labels;
2678 std::unordered_set<std::string> cached_object_data_labels;
2684 void incrementPrimitiveDataLabelCounter(
const std::string &primitive_data_label);
2690 void decrementPrimitiveDataLabelCounter(
const std::string &primitive_data_label);
2697 void incrementObjectDataLabelCounter(
const std::string &object_data_label);
2703 void decrementObjectDataLabelCounter(
const std::string &object_data_label);
2729 std::minstd_rand0 generator;
2732 std::uniform_real_distribution<float> unif_distribution;
2735 std::normal_distribution<float> norm_distribution;
2739 std::vector<std::string> XMLfiles;
2741 struct OBJmaterial {
2744 std::string texture;
2746 bool textureHasTransparency =
false;
2747 bool textureColorIsOverridden =
false;
2749 OBJmaterial(
const RGBcolor &a_color, std::string a_texture,
uint a_materialID) : color{a_color}, texture{std::move(a_texture)}, materialID{a_materialID} {};
2752 std::map<std::string, OBJmaterial> loadMTL(
const std::string &filebase,
const std::string &material_file,
const RGBcolor &default_color);
2754 void loadMaterialData(pugi::xml_node mat_node,
const std::string &material_label);
2756 void loadPData(pugi::xml_node p,
uint UUID);
2758 void loadOData(pugi::xml_node p,
uint ID);
2760 void loadOsubPData(pugi::xml_node p,
uint ID);
2762 void writeDataToXMLstream(
const char *data_group,
const std::vector<std::string> &data_labels,
void *ptr, std::ofstream &outfile)
const;
2769 uint currentObjectID;
2778 static void out_of_memory_handler();
2784 static void install_out_of_memory_handler();
2805 static int selfTest(
int argc,
char **argv);
3057 void rotatePrimitive(
const std::vector<uint> &UUIDs,
float rotation_rad,
const char *axis);
3073 void rotatePrimitive(
const std::vector<uint> &UUIDs,
float rotation_rad,
const vec3 &axis);
3179 std::vector<uint>
copyPrimitive(
const std::vector<uint> &UUIDs);
3272 [[nodiscard]]
size_t getPrimitiveCount(
bool include_hidden_primitives =
true)
const;
3279 [[nodiscard]]
size_t getTriangleCount(
bool include_hidden_primitives =
true)
const;
3286 [[nodiscard]]
size_t getPatchCount(
bool include_hidden_primitives =
true)
const;
3289 [[nodiscard]] std::vector<uint>
getAllUUIDs()
const;
3296 [[nodiscard]] std::vector<uint>
getDirtyUUIDs(
bool include_deleted_UUIDs =
false)
const;
3351 void cleanDeletedUUIDs(std::vector<std::vector<std::vector<uint>>> &UUIDs)
const;
3362 template<
typename T>
3365 if (primitives.find(UUID) == primitives.end()) {
3366 helios_runtime_error(
"ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3370 std::string label_str = std::string(label);
3371 bool had_cached_value =
false;
3374 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3376 T old_cached_value{};
3377 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
3379 had_cached_value =
true;
3381 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
3383 std::string old_cached_value;
3384 primitives.at(UUID)->getPrimitiveData(label, old_cached_value);
3386 had_cached_value =
true;
3390 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3391 incrementPrimitiveDataLabelCounter(label);
3396 if constexpr (std::is_same_v<T, int>) {
3398 }
else if constexpr (std::is_same_v<T, uint>) {
3400 }
else if constexpr (std::is_same_v<T, float>) {
3402 }
else if constexpr (std::is_same_v<T, double>) {
3404 }
else if constexpr (std::is_same_v<T, vec2>) {
3406 }
else if constexpr (std::is_same_v<T, vec3>) {
3408 }
else if constexpr (std::is_same_v<T, vec4>) {
3410 }
else if constexpr (std::is_same_v<T, int2>) {
3412 }
else if constexpr (std::is_same_v<T, int3>) {
3414 }
else if constexpr (std::is_same_v<T, int4>) {
3416 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
3419 HeliosDataType target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
3422 if (target_type != data_type && isTypeCastingSupported(data_type, target_type)) {
3423 storeDataWithTypeCasting(UUID, label, data, target_type);
3425 primitives.at(UUID)->setPrimitiveData(label, data);
3430 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3432 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
3437 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
3439 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
3452 template<
typename T>
3455 if (primitives.find(UUID) == primitives.end()) {
3456 helios_runtime_error(
"ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3459 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3460 incrementPrimitiveDataLabelCounter(label);
3465 if constexpr (std::is_same_v<T, int>) {
3467 }
else if constexpr (std::is_same_v<T, uint>) {
3469 }
else if constexpr (std::is_same_v<T, float>) {
3471 }
else if constexpr (std::is_same_v<T, double>) {
3473 }
else if constexpr (std::is_same_v<T, vec2>) {
3475 }
else if constexpr (std::is_same_v<T, vec3>) {
3477 }
else if constexpr (std::is_same_v<T, vec4>) {
3479 }
else if constexpr (std::is_same_v<T, int2>) {
3481 }
else if constexpr (std::is_same_v<T, int3>) {
3483 }
else if constexpr (std::is_same_v<T, int4>) {
3485 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
3488 registerOrValidatePrimitiveDataType<T>(label, data_type);
3490 primitives.at(UUID)->setPrimitiveData(label, data);
3501 template<
typename T>
3502 void setPrimitiveData(
const std::vector<uint> &UUIDs,
const char *label,
const std::vector<T> &data) {
3504 if (UUIDs.size() != data.size()) {
3505 helios_runtime_error(
"ERROR (Context::setPrimitiveData): UUIDs and data vectors must be the same size.");
3511 if (!UUIDs.empty()) {
3513 if constexpr (std::is_same_v<T, int>) {
3515 }
else if constexpr (std::is_same_v<T, uint>) {
3517 }
else if constexpr (std::is_same_v<T, float>) {
3519 }
else if constexpr (std::is_same_v<T, double>) {
3521 }
else if constexpr (std::is_same_v<T, vec2>) {
3523 }
else if constexpr (std::is_same_v<T, vec3>) {
3525 }
else if constexpr (std::is_same_v<T, vec4>) {
3527 }
else if constexpr (std::is_same_v<T, int2>) {
3529 }
else if constexpr (std::is_same_v<T, int3>) {
3531 }
else if constexpr (std::is_same_v<T, int4>) {
3533 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
3536 target_type = registerOrValidatePrimitiveDataType<T>(label, data_type);
3539 for (
uint UUID: UUIDs) {
3541 if (primitives.find(UUID) == primitives.end()) {
3542 helios_runtime_error(
"ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3545 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3546 incrementPrimitiveDataLabelCounter(label);
3551#pragma omp parallel for
3553 for (
int i = 0; i < (int) UUIDs.size(); ++i) {
3554 primitives.at(UUIDs[i])->setPrimitiveData(label, data[i]);
3565 template<
typename T>
3569 if (!UUIDs.empty()) {
3571 if constexpr (std::is_same_v<T, int>) {
3573 }
else if constexpr (std::is_same_v<T, uint>) {
3575 }
else if constexpr (std::is_same_v<T, float>) {
3577 }
else if constexpr (std::is_same_v<T, double>) {
3579 }
else if constexpr (std::is_same_v<T, vec2>) {
3581 }
else if constexpr (std::is_same_v<T, vec3>) {
3583 }
else if constexpr (std::is_same_v<T, vec4>) {
3585 }
else if constexpr (std::is_same_v<T, int2>) {
3587 }
else if constexpr (std::is_same_v<T, int3>) {
3589 }
else if constexpr (std::is_same_v<T, int4>) {
3591 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
3594 registerOrValidatePrimitiveDataType<T>(label, data_type);
3597 for (
uint UUID: UUIDs) {
3599 if (primitives.find(UUID) == primitives.end()) {
3600 helios_runtime_error(
"ERROR (Context::setPrimitiveData): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3603 if (!primitives.at(UUID)->doesPrimitiveDataExist(label)) {
3604 incrementPrimitiveDataLabelCounter(label);
3609#pragma omp parallel for
3611 for (
int i = 0; i < (int) UUIDs.size(); ++i) {
3612 primitives.at(UUIDs[i])->setPrimitiveData(label, data);
3623 template<
typename T>
3626 if (primitives.find(UUID) == primitives.end()) {
3627 helios_runtime_error(
"ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3630 primitives.at(UUID)->getPrimitiveData(label, data);
3641 template<
typename T>
3644 if (primitives.find(UUID) == primitives.end()) {
3645 helios_runtime_error(
"ERROR (Context::getPrimitiveData): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
3648 primitives.at(UUID)->getPrimitiveData(label, data);
3828 void hideObject(
const std::vector<uint> &ObjIDs);
3840 void showObject(
const std::vector<uint> &ObjIDs);
4193 void addMaterial(
const std::string &material_label);
4201 void renameMaterial(
const std::string &old_label,
const std::string &new_label);
4214 [[nodiscard]] std::vector<std::string>
listMaterials()
const;
4228 [[nodiscard]] std::string
getMaterialTexture(
const std::string &material_label)
const;
4251 void setMaterialTexture(
const std::string &material_label,
const std::string &texture_file);
4348 template<
typename T>
4349 void setMaterialData(
const std::string &material_label,
const char *data_label,
const T &data) {
4351 materials[matID].setMaterialData(data_label, data);
4362 template<
typename T>
4363 void setMaterialData(
const std::string &material_label,
const char *data_label,
const std::vector<T> &data) {
4365 materials[matID].setMaterialData(data_label, data);
4375 template<
typename T>
4376 void getMaterialData(
const std::string &material_label,
const char *data_label, T &data)
const {
4378 materials.at(matID).getMaterialData(data_label, data);
4388 template<
typename T>
4389 void getMaterialData(
const std::string &material_label,
const char *data_label, std::vector<T> &data)
const {
4391 materials.at(matID).getMaterialData(data_label, data);
4400 [[nodiscard]]
bool doesMaterialDataExist(
const std::string &material_label,
const char *data_label)
const;
4415 void clearMaterialData(
const std::string &material_label,
const char *data_label);
4428 template<
typename T>
4430 Primitive *prim = getPrimitivePointer_private(UUID);
4431 uint materialID = prim->materialID;
4434 if (materials.find(materialID) != materials.end() && materials.at(materialID).doesMaterialDataExist(data_label)) {
4435 materials.at(materialID).getMaterialData(data_label, data);
4438 else if (prim->doesPrimitiveDataExist(data_label)) {
4439 prim->getPrimitiveData(data_label, data);
4443 helios_runtime_error(
"ERROR (Context::getDataWithMaterialFallback): Data " + std::string(data_label) +
" does not exist for primitive " + std::to_string(UUID) +
" (neither in its material nor as primitive data).");
4483 template<
typename T>
4486 if (objects.find(objID) == objects.end()) {
4487 helios_runtime_error(
"ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) +
" does not exist in the Context.");
4490 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4491 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
4492 "Context::setObjectData() was called with an unsupported type.");
4496 if constexpr (std::is_same_v<T, int>) {
4498 }
else if constexpr (std::is_same_v<T, uint>) {
4500 }
else if constexpr (std::is_same_v<T, float>) {
4502 }
else if constexpr (std::is_same_v<T, double>) {
4504 }
else if constexpr (std::is_same_v<T, vec2>) {
4506 }
else if constexpr (std::is_same_v<T, vec3>) {
4508 }
else if constexpr (std::is_same_v<T, vec4>) {
4510 }
else if constexpr (std::is_same_v<T, int2>) {
4512 }
else if constexpr (std::is_same_v<T, int3>) {
4514 }
else if constexpr (std::is_same_v<T, int4>) {
4516 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4519 registerOrValidateObjectDataType<T>(label, data_type);
4522 std::string label_str = std::string(label);
4523 bool had_cached_value =
false;
4526 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4528 T old_cached_value{};
4529 objects.at(objID)->getObjectData(label, old_cached_value);
4531 had_cached_value =
true;
4533 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4535 std::string old_cached_value;
4536 objects.at(objID)->getObjectData(label, old_cached_value);
4538 had_cached_value =
true;
4542 if (!objects.at(objID)->doesObjectDataExist(label)) {
4543 incrementObjectDataLabelCounter(label);
4545 objects.at(objID)->setObjectData(label, data);
4549 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4551 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4556 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4558 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4571 template<
typename T>
4572 void setObjectData(
const std::vector<uint> &objIDs,
const char *label,
const T &data) {
4573 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4574 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
4575 "Context::setObjectData() was called with an unsupported type.");
4578 if (!objIDs.empty()) {
4580 if constexpr (std::is_same_v<T, int>) {
4582 }
else if constexpr (std::is_same_v<T, uint>) {
4584 }
else if constexpr (std::is_same_v<T, float>) {
4586 }
else if constexpr (std::is_same_v<T, double>) {
4588 }
else if constexpr (std::is_same_v<T, vec2>) {
4590 }
else if constexpr (std::is_same_v<T, vec3>) {
4592 }
else if constexpr (std::is_same_v<T, vec4>) {
4594 }
else if constexpr (std::is_same_v<T, int2>) {
4596 }
else if constexpr (std::is_same_v<T, int3>) {
4598 }
else if constexpr (std::is_same_v<T, int4>) {
4600 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4603 registerOrValidateObjectDataType<T>(label, data_type);
4607 std::string label_str = std::string(label);
4611 if (caching_enabled) {
4613 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4614 for (
uint objID: objIDs) {
4615 if (objects.at(objID)->doesObjectDataExist(label)) {
4616 T old_cached_value{};
4617 objects.at(objID)->getObjectData(label, old_cached_value);
4621 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4622 for (
uint objID: objIDs) {
4623 if (objects.at(objID)->doesObjectDataExist(label)) {
4624 std::string old_cached_value;
4625 objects.at(objID)->getObjectData(label, old_cached_value);
4633 for (
uint objID: objIDs) {
4634 if (!objects.at(objID)->doesObjectDataExist(label)) {
4635 incrementObjectDataLabelCounter(label);
4640#pragma omp parallel for
4642 for (
int i = 0; i < (int) objIDs.size(); ++i) {
4643 objects.at(objIDs[i])->setObjectData(label, data);
4647 if (caching_enabled) {
4648 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4650 for (
size_t i = 0; i < objIDs.size(); ++i) {
4653 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4655 for (
size_t i = 0; i < objIDs.size(); ++i) {
4669 template<
typename T>
4670 void setObjectData(
const std::vector<std::vector<uint>> &objIDs,
const char *label,
const T &data) {
4671 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4672 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
4673 "Context::setObjectData() was called with an unsupported type.");
4676 if (!objIDs.empty() && !objIDs[0].empty()) {
4678 if constexpr (std::is_same_v<T, int>) {
4680 }
else if constexpr (std::is_same_v<T, uint>) {
4682 }
else if constexpr (std::is_same_v<T, float>) {
4684 }
else if constexpr (std::is_same_v<T, double>) {
4686 }
else if constexpr (std::is_same_v<T, vec2>) {
4688 }
else if constexpr (std::is_same_v<T, vec3>) {
4690 }
else if constexpr (std::is_same_v<T, vec4>) {
4692 }
else if constexpr (std::is_same_v<T, int2>) {
4694 }
else if constexpr (std::is_same_v<T, int3>) {
4696 }
else if constexpr (std::is_same_v<T, int4>) {
4698 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4701 registerOrValidateObjectDataType<T>(label, data_type);
4705 std::string label_str = std::string(label);
4707 size_t total_objects = 0;
4710 if (caching_enabled) {
4712 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4713 for (
const auto &j: objIDs) {
4714 for (
uint objID: j) {
4716 if (objects.at(objID)->doesObjectDataExist(label)) {
4717 T old_cached_value{};
4718 objects.at(objID)->getObjectData(label, old_cached_value);
4723 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4724 for (
const auto &j: objIDs) {
4725 for (
uint objID: j) {
4727 if (objects.at(objID)->doesObjectDataExist(label)) {
4728 std::string old_cached_value;
4729 objects.at(objID)->getObjectData(label, old_cached_value);
4737 for (
const auto &j: objIDs) {
4738 total_objects += j.size();
4742 for (
const auto &j: objIDs) {
4743 for (
uint objID: j) {
4744 if (!objects.at(objID)->doesObjectDataExist(label)) {
4745 incrementObjectDataLabelCounter(label);
4751#pragma omp parallel for
4753 for (
int j = 0; j < (int) objIDs.size(); ++j) {
4754 for (
size_t i = 0; i < objIDs[j].size(); ++i) {
4755 objects.at(objIDs[j][i])->setObjectData(label, data);
4760 if (caching_enabled) {
4761 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4763 for (
size_t i = 0; i < total_objects; ++i) {
4766 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4768 for (
size_t i = 0; i < total_objects; ++i) {
4782 template<
typename T>
4783 void setObjectData(
const std::vector<std::vector<std::vector<uint>>> &objIDs,
const char *label,
const T &data) {
4784 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4785 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
4786 "Context::setObjectData() was called with an unsupported type.");
4789 if (!objIDs.empty() && !objIDs[0].empty() && !objIDs[0][0].empty()) {
4791 if constexpr (std::is_same_v<T, int>) {
4793 }
else if constexpr (std::is_same_v<T, uint>) {
4795 }
else if constexpr (std::is_same_v<T, float>) {
4797 }
else if constexpr (std::is_same_v<T, double>) {
4799 }
else if constexpr (std::is_same_v<T, vec2>) {
4801 }
else if constexpr (std::is_same_v<T, vec3>) {
4803 }
else if constexpr (std::is_same_v<T, vec4>) {
4805 }
else if constexpr (std::is_same_v<T, int2>) {
4807 }
else if constexpr (std::is_same_v<T, int3>) {
4809 }
else if constexpr (std::is_same_v<T, int4>) {
4811 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4814 registerOrValidateObjectDataType<T>(label, data_type);
4818 std::string label_str = std::string(label);
4820 size_t total_objects = 0;
4823 if (caching_enabled) {
4825 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4826 for (
const auto &k: objIDs) {
4827 for (
const auto &j: k) {
4828 for (
uint objID: j) {
4830 if (objects.at(objID)->doesObjectDataExist(label)) {
4831 T old_cached_value{};
4832 objects.at(objID)->getObjectData(label, old_cached_value);
4838 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4839 for (
const auto &k: objIDs) {
4840 for (
const auto &j: k) {
4841 for (
uint objID: j) {
4843 if (objects.at(objID)->doesObjectDataExist(label)) {
4844 std::string old_cached_value;
4845 objects.at(objID)->getObjectData(label, old_cached_value);
4854 for (
const auto &k: objIDs) {
4855 for (
const auto &j: k) {
4856 total_objects += j.size();
4861 for (
const auto &k: objIDs) {
4862 for (
const auto &j: k) {
4863 for (
uint objID: j) {
4864 if (!objects.at(objID)->doesObjectDataExist(label)) {
4865 incrementObjectDataLabelCounter(label);
4872#pragma omp parallel for
4874 for (
int k = 0; k < (int) objIDs.size(); ++k) {
4875 for (
size_t j = 0; j < objIDs[k].size(); ++j) {
4876 for (
size_t i = 0; i < objIDs[k][j].size(); ++i) {
4877 uint objID = objIDs[k][j][i];
4878 objects.at(objID)->setObjectData(label, data);
4884 if (caching_enabled) {
4885 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>) {
4887 for (
size_t i = 0; i < total_objects; ++i) {
4890 }
else if constexpr (std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4892 for (
size_t i = 0; i < total_objects; ++i) {
4907 template<
typename T>
4910 if (objects.find(objID) == objects.end()) {
4911 helios_runtime_error(
"ERROR (Context::setObjectData): Object ID of " + std::to_string(objID) +
" does not exist in the Context.");
4914 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4915 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
4916 "Context::setObjectData() was called with an unsupported type.");
4920 if constexpr (std::is_same_v<T, int>) {
4922 }
else if constexpr (std::is_same_v<T, uint>) {
4924 }
else if constexpr (std::is_same_v<T, float>) {
4926 }
else if constexpr (std::is_same_v<T, double>) {
4928 }
else if constexpr (std::is_same_v<T, vec2>) {
4930 }
else if constexpr (std::is_same_v<T, vec3>) {
4932 }
else if constexpr (std::is_same_v<T, vec4>) {
4934 }
else if constexpr (std::is_same_v<T, int2>) {
4936 }
else if constexpr (std::is_same_v<T, int3>) {
4938 }
else if constexpr (std::is_same_v<T, int4>) {
4940 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4943 registerOrValidateObjectDataType<T>(label, data_type);
4945 objects.at(objID)->setObjectData(label, data);
4956 template<
typename T>
4957 void setObjectData(
const std::vector<uint> &objIDs,
const char *label,
const std::vector<T> &data) {
4959 if (objIDs.size() != data.size()) {
4960 helios_runtime_error(
"ERROR (Context::setObjectData): Object IDs and data vectors must be the same size.");
4963 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
4964 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
4965 "Context::setObjectData() was called with an unsupported type.");
4968 if (!objIDs.empty()) {
4970 if constexpr (std::is_same_v<T, int>) {
4972 }
else if constexpr (std::is_same_v<T, uint>) {
4974 }
else if constexpr (std::is_same_v<T, float>) {
4976 }
else if constexpr (std::is_same_v<T, double>) {
4978 }
else if constexpr (std::is_same_v<T, vec2>) {
4980 }
else if constexpr (std::is_same_v<T, vec3>) {
4982 }
else if constexpr (std::is_same_v<T, vec4>) {
4984 }
else if constexpr (std::is_same_v<T, int2>) {
4986 }
else if constexpr (std::is_same_v<T, int3>) {
4988 }
else if constexpr (std::is_same_v<T, int4>) {
4990 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
4993 registerOrValidateObjectDataType<T>(label, data_type);
4996 for (
uint objID: objIDs) {
4997 if (!objects.at(objID)->doesObjectDataExist(label)) {
4998 incrementObjectDataLabelCounter(label);
5003#pragma omp parallel for
5005 for (
int i = 0; i < (int) objIDs.size(); ++i) {
5006 objects.at(objIDs[i])->setObjectData(label, data[i]);
5027 template<
typename T>
5030 if (objects.find(objID) == objects.end()) {
5031 helios_runtime_error(
"ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) +
" does not exist in the Context.");
5034 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5035 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
5036 "Context::getObjectData() was called with an unsupported type.");
5037 objects.at(objID)->getObjectData(label, data);
5048 template<
typename T>
5051 if (objects.find(objID) == objects.end()) {
5052 helios_runtime_error(
"ERROR (Context::getObjectData): Object ID of " + std::to_string(objID) +
" does not exist in the Context.");
5055 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5056 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>,
5057 "Context::getObjectData() was called with an unsupported type.");
5058 objects.at(objID)->getObjectData(label, data);
5108 void clearObjectData(
const std::vector<uint> &objIDs,
const char *label);
5148 template<
typename T>
5150 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5151 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *> || std::is_same_v<T, bool>,
5152 "Context::setGlobalData() was called with an unsupported type.");
5154 globaldata[label].size = 1;
5155 if constexpr (std::is_same_v<T, int>) {
5156 globaldata[label].global_data_int = {data};
5158 }
else if constexpr (std::is_same_v<T, uint>) {
5159 globaldata[label].global_data_uint = {data};
5161 }
else if constexpr (std::is_same_v<T, float>) {
5162 globaldata[label].global_data_float = {data};
5164 }
else if constexpr (std::is_same_v<T, double>) {
5165 globaldata[label].global_data_double = {data};
5167 }
else if constexpr (std::is_same_v<T, vec2>) {
5168 globaldata[label].global_data_vec2 = {data};
5170 }
else if constexpr (std::is_same_v<T, vec3>) {
5171 globaldata[label].global_data_vec3 = {data};
5173 }
else if constexpr (std::is_same_v<T, vec4>) {
5174 globaldata[label].global_data_vec4 = {data};
5176 }
else if constexpr (std::is_same_v<T, int2>) {
5177 globaldata[label].global_data_int2 = {data};
5179 }
else if constexpr (std::is_same_v<T, int3>) {
5180 globaldata[label].global_data_int3 = {data};
5182 }
else if constexpr (std::is_same_v<T, int4>) {
5183 globaldata[label].global_data_int4 = {data};
5185 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
5186 globaldata[label].global_data_string = {data};
5188 }
else if constexpr (std::is_same_v<T, bool>) {
5189 globaldata[label].global_data_bool = {data};
5192 globaldata[label].version++;
5200 template<
typename T>
5202 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5203 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *> || std::is_same_v<T, bool>,
5204 "Context::setGlobalData() was called with an unsupported type.");
5206 globaldata[label].size = data.size();
5207 if constexpr (std::is_same_v<T, int>) {
5208 globaldata[label].global_data_int = data;
5210 }
else if constexpr (std::is_same_v<T, uint>) {
5211 globaldata[label].global_data_uint = data;
5213 }
else if constexpr (std::is_same_v<T, float>) {
5214 globaldata[label].global_data_float = data;
5216 }
else if constexpr (std::is_same_v<T, double>) {
5217 globaldata[label].global_data_double = data;
5219 }
else if constexpr (std::is_same_v<T, vec2>) {
5220 globaldata[label].global_data_vec2 = data;
5222 }
else if constexpr (std::is_same_v<T, vec3>) {
5223 globaldata[label].global_data_vec3 = data;
5225 }
else if constexpr (std::is_same_v<T, vec4>) {
5226 globaldata[label].global_data_vec4 = data;
5228 }
else if constexpr (std::is_same_v<T, int2>) {
5229 globaldata[label].global_data_int2 = data;
5231 }
else if constexpr (std::is_same_v<T, int3>) {
5232 globaldata[label].global_data_int3 = data;
5234 }
else if constexpr (std::is_same_v<T, int4>) {
5235 globaldata[label].global_data_int4 = data;
5237 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
5238 globaldata[label].global_data_string = data;
5240 }
else if constexpr (std::is_same_v<T, bool>) {
5241 globaldata[label].global_data_bool = data;
5244 globaldata[label].version++;
5252 template<
typename T>
5255 if constexpr (std::is_same_v<T, std::vector<int>>) {
5258 data = globaldata.at(label).global_data_int;
5260 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) +
" does not have type int.");
5262 }
else if constexpr (std::is_same_v<T, std::vector<uint>>) {
5265 data = globaldata.at(label).global_data_uint;
5267 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) +
" does not have type uint.");
5269 }
else if constexpr (std::is_same_v<T, std::vector<float>>) {
5272 data = globaldata.at(label).global_data_float;
5274 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) +
" does not have type float.");
5276 }
else if constexpr (std::is_same_v<T, std::vector<double>>) {
5279 data = globaldata.at(label).global_data_double;
5281 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) +
" does not have type double.");
5283 }
else if constexpr (std::is_same_v<T, std::vector<vec2>>) {
5286 data = globaldata.at(label).global_data_vec2;
5288 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) +
" does not have type vec2.");
5290 }
else if constexpr (std::is_same_v<T, std::vector<vec3>>) {
5293 data = globaldata.at(label).global_data_vec3;
5295 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) +
" does not have type vec3.");
5297 }
else if constexpr (std::is_same_v<T, std::vector<vec4>>) {
5300 data = globaldata.at(label).global_data_vec4;
5302 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) +
" does not have type vec4.");
5304 }
else if constexpr (std::is_same_v<T, std::vector<int2>>) {
5307 data = globaldata.at(label).global_data_int2;
5309 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) +
" does not have type int2.");
5311 }
else if constexpr (std::is_same_v<T, std::vector<int3>>) {
5314 data = globaldata.at(label).global_data_int3;
5316 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) +
" does not have type int3.");
5318 }
else if constexpr (std::is_same_v<T, std::vector<int4>>) {
5321 data = globaldata.at(label).global_data_int4;
5323 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) +
" does not have type int4.");
5325 }
else if constexpr (std::is_same_v<T, std::vector<std::string>>) {
5328 data = globaldata.at(label).global_data_string;
5330 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) +
" does not have type string.");
5332 }
else if constexpr (std::is_same_v<T, int>) {
5335 data = globaldata.at(label).global_data_int.front();
5337 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int, but data " + std::string(label) +
" does not have type int.");
5339 }
else if constexpr (std::is_same_v<T, uint>) {
5342 data = globaldata.at(label).global_data_uint.front();
5344 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type uint, but data " + std::string(label) +
" does not have type uint.");
5346 }
else if constexpr (std::is_same_v<T, float>) {
5349 data = globaldata.at(label).global_data_float.front();
5351 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type float, but data " + std::string(label) +
" does not have type float.");
5353 }
else if constexpr (std::is_same_v<T, double>) {
5356 data = globaldata.at(label).global_data_double.front();
5358 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type double, but data " + std::string(label) +
" does not have type double.");
5360 }
else if constexpr (std::is_same_v<T, vec2>) {
5363 data = globaldata.at(label).global_data_vec2.front();
5365 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type vec2, but data " + std::string(label) +
" does not have type vec2.");
5367 }
else if constexpr (std::is_same_v<T, vec3>) {
5370 data = globaldata.at(label).global_data_vec3.front();
5372 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type vec3, but data " + std::string(label) +
" does not have type vec3.");
5374 }
else if constexpr (std::is_same_v<T, vec4>) {
5377 data = globaldata.at(label).global_data_vec4.front();
5379 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type vec4, but data " + std::string(label) +
" does not have type vec4.");
5381 }
else if constexpr (std::is_same_v<T, int2>) {
5384 data = globaldata.at(label).global_data_int2.front();
5386 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int2, but data " + std::string(label) +
" does not have type int2.");
5388 }
else if constexpr (std::is_same_v<T, int3>) {
5391 data = globaldata.at(label).global_data_int3.front();
5393 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int3, but data " + std::string(label) +
" does not have type int3.");
5395 }
else if constexpr (std::is_same_v<T, int4>) {
5398 data = globaldata.at(label).global_data_int4.front();
5400 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type int4, but data " + std::string(label) +
" does not have type int4.");
5402 }
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
5405 data = globaldata.at(label).global_data_string.front();
5407 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type string, but data " + std::string(label) +
" does not have type string.");
5409 }
else if constexpr (std::is_same_v<T, bool>) {
5412 data = globaldata.at(label).global_data_bool.front();
5414 helios_runtime_error(
"ERROR (Context::getGlobalData): Attempted to get data for type bool, but data " + std::string(label) +
" does not have type bool.");
5417 static_assert(std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, vec2> || std::is_same_v<T, vec3> || std::is_same_v<T, vec4> || std::is_same_v<T, int2> ||
5418 std::is_same_v<T, int3> || std::is_same_v<T, int4> || std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *> ||
5419 std::is_same_v<T, std::vector<int>> || std::is_same_v<T, std::vector<uint>> || std::is_same_v<T, std::vector<float>> || std::is_same_v<T, std::vector<double>> || std::is_same_v<T, std::vector<vec2>> ||
5420 std::is_same_v<T, std::vector<vec3>> || std::is_same_v<T, std::vector<vec4>> || std::is_same_v<T, std::vector<int2>> || std::is_same_v<T, std::vector<int3>> || std::is_same_v<T, std::vector<int4>> ||
5421 std::is_same_v<T, std::vector<std::string>> || std::is_same_v<T, std::vector<bool>>,
5422 "CompoundObject::getGlobalData() was called with an unsupported type.");
5557 std::vector<uint>
copyObject(
const std::vector<uint> &ObjIDs);
5589 std::vector<uint>
filterObjectsByData(
const std::vector<uint> &ObjIDs,
const char *object_data,
float threshold,
const char *comparator)
const;
5611 void rotateObject(
uint ObjID,
float rotation_radians,
const char *rotation_axis_xyz)
const;
5619 void rotateObject(
const std::vector<uint> &ObjIDs,
float rotation_radians,
const char *rotation_axis_xyz)
const;
5635 void rotateObject(
const std::vector<uint> &ObjIDs,
float rotation_radians,
const vec3 &rotation_axis_vector)
const;
5644 void rotateObject(
uint ObjID,
float rotation_radians,
const vec3 &rotation_origin,
const vec3 &rotation_axis_vector)
const;
5653 void rotateObject(
const std::vector<uint> &ObjIDs,
float rotation_radians,
const vec3 &rotation_origin,
const vec3 &rotation_axis_vector)
const;
6178 uint addTubeObject(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius);
6190 uint addTubeObject(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const std::vector<RGBcolor> &color);
6203 uint addTubeObject(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile);
6217 uint addTubeObject(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile,
const std::vector<float> &textureuv_ufrac);
6460 std::vector<uint>
addSphere(
uint Ndivs,
const vec3 ¢er,
float radius,
const char *texturefile);
6521 std::vector<uint>
addTube(
uint Ndivs,
const std::vector<vec3> &nodes,
const std::vector<float> &radius);
6533 std::vector<uint>
addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const std::vector<RGBcolor> &color);
6545 std::vector<uint>
addTube(
uint radial_subdivisions,
const std::vector<vec3> &nodes,
const std::vector<float> &radius,
const char *texturefile);
6581 std::vector<uint>
addBox(
const vec3 ¢er,
const vec3 &size,
const int3 &subdiv,
const char *texturefile);
6594 std::vector<uint>
addBox(
const vec3 ¢er,
const vec3 &size,
const int3 &subdiv,
const RGBcolor &color,
bool reverse_normals);
6607 std::vector<uint>
addBox(
const vec3 ¢er,
const vec3 &size,
const int3 &subdiv,
const char *texturefile,
bool reverse_normals);
6718 std::vector<uint>
addCone(
uint Ndivs,
const vec3 &node0,
const vec3 &node1,
float radius0,
float radius1);
6744 std::vector<uint>
addCone(
uint Ndivs,
const vec3 &node0,
const vec3 &node1,
float radius0,
float radius1,
const char *texturefile);
6875 void loadTabularTimeseriesData(
const std::string &data_file,
const std::vector<std::string> &column_labels,
const std::string &delimiter,
const std::string &date_string_format =
"YYYYMMDD",
uint headerlines = 0);
6934 void cropDomain(std::vector<uint> &UUIDs,
const vec2 &xbounds,
const vec2 &ybounds,
const vec2 &zbounds);
6962 void colorPrimitiveByDataPseudocolor(
const std::vector<uint> &UUIDs,
const std::string &primitive_data,
const std::string &colormap,
uint Ncolors,
float data_min,
float data_max);
6971 std::vector<uint>
loadXML(
const char *filename,
bool quiet =
false);
6986 static bool scanXMLForTag(
const std::string &filename,
const std::string &tag,
const std::string &label =
"");
6993 void writeXML(
const char *filename,
bool quiet =
false)
const;
7001 void writeXML(
const char *filename,
const std::vector<uint> &UUIDs,
bool quiet =
false)
const;
7009 void writeXML_byobject(
const char *filename,
const std::vector<uint> &UUIDs,
bool quiet =
false)
const;
7017 void writePrimitiveData(
const std::string &filename,
const std::vector<std::string> &column_format,
bool print_header =
false)
const;
7026 void writePrimitiveData(
const std::string &filename,
const std::vector<std::string> &column_format,
const std::vector<uint> &UUIDs,
bool print_header =
false)
const;
7035 std::vector<uint>
loadPLY(
const char *filename,
bool silent =
false);
7047 std::vector<uint>
loadPLY(
const char *filename,
const vec3 &origin,
float height,
const std::string &upaxis =
"YUP",
bool silent =
false);
7060 std::vector<uint>
loadPLY(
const char *filename,
const vec3 &origin,
float height,
const SphericalCoord &rotation,
const std::string &upaxis =
"YUP",
bool silent =
false);
7072 std::vector<uint>
loadPLY(
const char *filename,
const vec3 &origin,
float height,
const RGBcolor &default_color,
const std::string &upaxis =
"YUP",
bool silent =
false);
7085 std::vector<uint>
loadPLY(
const char *filename,
const vec3 &origin,
float height,
const SphericalCoord &rotation,
const RGBcolor &default_color,
const std::string &upaxis =
"YUP",
bool silent =
false);
7091 void writePLY(
const char *filename)
const;
7098 void writePLY(
const char *filename,
const std::vector<uint> &UUIDs)
const;
7107 std::vector<uint>
loadOBJ(
const char *filename,
bool silent =
false);
7119 std::vector<uint>
loadOBJ(
const char *filename,
const vec3 &origin,
float height,
const SphericalCoord &rotation,
const RGBcolor &default_color,
bool silent =
false);
7132 std::vector<uint>
loadOBJ(
const char *filename,
const vec3 &origin,
float height,
const SphericalCoord &rotation,
const RGBcolor &default_color,
const char *upaxis,
bool silent =
false);
7154 void writeOBJ(
const std::string &filename,
bool write_normals =
false,
bool silent =
false)
const;
7163 void writeOBJ(
const std::string &filename,
const std::vector<uint> &UUIDs,
bool write_normals =
false,
bool silent =
false)
const;
7173 void writeOBJ(
const std::string &filename,
const std::vector<uint> &UUIDs,
const std::vector<std::string> &primitive_dat_fields,
bool write_normals =
false,
bool silent =
false)
const;
7183 std::filesystem::path
resolveFilePath(
const std::string &filename)
const;
7192 void setDate(
int day,
int month,
int year);
7207 void setDate(
int Julian_day,
int year);
7237 void setTime(
int minute,
int hour);
7247 void setTime(
int second,
int minute,
int hour);
7486 void scalePrimitiveData(
const std::vector<uint> &UUIDs,
const std::string &label,
float scaling_factor);
7539 void aggregatePrimitiveDataSum(
const std::vector<uint> &UUIDs,
const std::vector<std::string> &primitive_data_labels,
const std::string &result_primitive_data_label);
7548 void aggregatePrimitiveDataProduct(
const std::vector<uint> &UUIDs,
const std::vector<std::string> &primitive_data_labels,
const std::string &result_primitive_data_label);
7566 [[nodiscard]] std::vector<uint>
filterPrimitivesByData(
const std::vector<uint> &UUIDs,
const std::string &primitive_data_label,
float filter_value,
const std::string &comparator)
const;
7577 [[nodiscard]] std::vector<uint>
filterPrimitivesByData(
const std::vector<uint> &UUIDs,
const std::string &primitive_data_label,
double filter_value,
const std::string &comparator)
const;
7588 [[nodiscard]] std::vector<uint>
filterPrimitivesByData(
const std::vector<uint> &UUIDs,
const std::string &primitive_data_label,
int filter_value,
const std::string &comparator)
const;
7599 [[nodiscard]] std::vector<uint>
filterPrimitivesByData(
const std::vector<uint> &UUIDs,
const std::string &primitive_data_label,
uint filter_value,
const std::string &comparator)
const;
7609 [[nodiscard]] std::vector<uint>
filterPrimitivesByData(
const std::vector<uint> &UUIDs,
const std::string &primitive_data_label,
const std::string &filter_value)
const;
7620 [[nodiscard]] std::vector<uint>
filterObjectsByData(
const std::vector<uint> &objIDs,
const std::string &object_data_label,
float filter_value,
const std::string &comparator)
const;
7631 [[nodiscard]] std::vector<uint>
filterObjectsByData(
const std::vector<uint> &objIDs,
const std::string &object_data_label,
double filter_value,
const std::string &comparator)
const;
7642 [[nodiscard]] std::vector<uint>
filterObjectsByData(
const std::vector<uint> &objIDs,
const std::string &object_data_label,
int filter_value,
const std::string &comparator)
const;
7653 [[nodiscard]] std::vector<uint>
filterObjectsByData(
const std::vector<uint> &objIDs,
const std::string &object_data_label,
uint filter_value,
const std::string &comparator)
const;
7663 [[nodiscard]] std::vector<uint>
filterObjectsByData(
const std::vector<uint> &objIDs,
const std::string &object_data_label,
const std::string &filter_value)
const;
7694 std::vector<RGBcolor>
generateColormap(
const std::vector<helios::RGBcolor> &ctable,
const std::vector<float> &cfrac,
uint Ncolors);
7698 template<
typename T>
7699 void storeDataWithTypeCasting(
uint UUID,
const char *label,
const T &data,
HeliosDataType target_type) {
7701 if constexpr (std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double>) {
7702 if (target_type == HELIOS_TYPE_INT) {
7703 primitives.at(UUID)->setPrimitiveData(label,
static_cast<int>(data));
7704 }
else if (target_type == HELIOS_TYPE_UINT) {
7705 primitives.at(UUID)->setPrimitiveData(label,
static_cast<uint>(data));
7706 }
else if (target_type == HELIOS_TYPE_FLOAT) {
7707 primitives.at(UUID)->setPrimitiveData(label,
static_cast<float>(data));
7708 }
else if (target_type == HELIOS_TYPE_DOUBLE) {
7709 primitives.at(UUID)->setPrimitiveData(label,
static_cast<double>(data));
7712 primitives.at(UUID)->setPrimitiveData(label, data);
7716 primitives.at(UUID)->setPrimitiveData(label, data);
7720 template<
typename T>
7721 void storeObjectDataWithTypeCasting(
uint objID,
const char *label,
const T &data, HeliosDataType target_type) {
7723 if constexpr (std::is_same_v<T, int> || std::is_same_v<T, uint> || std::is_same_v<T, float> || std::is_same_v<T, double>) {
7724 if (target_type == HELIOS_TYPE_INT) {
7725 objects.at(objID)->setObjectData(label,
static_cast<int>(data));
7726 }
else if (target_type == HELIOS_TYPE_UINT) {
7727 objects.at(objID)->setObjectData(label,
static_cast<uint>(data));
7728 }
else if (target_type == HELIOS_TYPE_FLOAT) {
7729 objects.at(objID)->setObjectData(label,
static_cast<float>(data));
7730 }
else if (target_type == HELIOS_TYPE_DOUBLE) {
7731 objects.at(objID)->setObjectData(label,
static_cast<double>(data));
7734 objects.at(objID)->setObjectData(label, data);
7738 objects.at(objID)->setObjectData(label, data);
7742 template<
typename T>
7743 HeliosDataType registerOrValidatePrimitiveDataType(
const std::string &label, HeliosDataType data_type) {
7744 auto it = primitive_data_type_registry.find(label);
7745 if (it == primitive_data_type_registry.end()) {
7747 primitive_data_type_registry[label] = data_type;
7752 if (expected_type != data_type) {
7754 if (!isTypeCastingSupported(data_type, expected_type)) {
7755 helios_runtime_error(
"ERROR (Context::registerOrValidatePrimitiveDataType): Data type mismatch for label '" + label +
"'. Expected " + dataTypeToString(expected_type) +
" but got " + dataTypeToString(data_type) +
7756 ". Type casting between these types is not supported.");
7758 std::cerr <<
"WARNING (Context::registerOrValidatePrimitiveDataType): Type casting from " + dataTypeToString(data_type) +
" to " + dataTypeToString(expected_type) +
" for label '" + label +
7759 "'. Consider using consistent types."
7763 return expected_type;
7767 template<
typename T>
7768 HeliosDataType registerOrValidateObjectDataType(
const std::string &label, HeliosDataType data_type) {
7769 auto it = object_data_type_registry.find(label);
7770 if (it == object_data_type_registry.end()) {
7772 object_data_type_registry[label] = data_type;
7777 if (expected_type != data_type) {
7779 if (!isTypeCastingSupported(data_type, expected_type)) {
7780 helios_runtime_error(
"ERROR (Context::registerOrValidateObjectDataType): Data type mismatch for label '" + label +
"'. Expected " + dataTypeToString(expected_type) +
" but got " + dataTypeToString(data_type) +
7781 ". Type casting between these types is not supported.");
7783 std::cerr <<
"WARNING (Context::registerOrValidateObjectDataType): Type casting from " + dataTypeToString(data_type) +
" to " + dataTypeToString(expected_type) +
" for label '" + label +
"'. Consider using consistent types."
7787 return expected_type;
7794 template<
typename T>
7796 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
7797 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7798 primitive_string_value_registry[label][string_value]++;
7799 }
else if constexpr (std::is_same_v<T, int>) {
7800 primitive_int_value_registry[label][value]++;
7801 }
else if constexpr (std::is_same_v<T, uint>) {
7802 primitive_uint_value_registry[label][value]++;
7807 template<
typename T>
7809 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
7810 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7811 auto label_it = primitive_string_value_registry.find(label);
7812 if (label_it != primitive_string_value_registry.end()) {
7813 auto value_it = label_it->second.find(string_value);
7814 if (value_it != label_it->second.end() && value_it->second > 0) {
7816 if (value_it->second == 0) {
7817 label_it->second.erase(value_it);
7818 if (label_it->second.empty()) {
7819 primitive_string_value_registry.erase(label_it);
7824 }
else if constexpr (std::is_same_v<T, int>) {
7825 auto label_it = primitive_int_value_registry.find(label);
7826 if (label_it != primitive_int_value_registry.end()) {
7827 auto value_it = label_it->second.find(value);
7828 if (value_it != label_it->second.end() && value_it->second > 0) {
7830 if (value_it->second == 0) {
7831 label_it->second.erase(value_it);
7832 if (label_it->second.empty()) {
7833 primitive_int_value_registry.erase(label_it);
7838 }
else if constexpr (std::is_same_v<T, uint>) {
7839 auto label_it = primitive_uint_value_registry.find(label);
7840 if (label_it != primitive_uint_value_registry.end()) {
7841 auto value_it = label_it->second.find(value);
7842 if (value_it != label_it->second.end() && value_it->second > 0) {
7844 if (value_it->second == 0) {
7845 label_it->second.erase(value_it);
7846 if (label_it->second.empty()) {
7847 primitive_uint_value_registry.erase(label_it);
7856 template<
typename T>
7858 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
7859 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7860 object_string_value_registry[label][string_value]++;
7861 }
else if constexpr (std::is_same_v<T, int>) {
7862 object_int_value_registry[label][value]++;
7863 }
else if constexpr (std::is_same_v<T, uint>) {
7864 object_uint_value_registry[label][value]++;
7869 template<
typename T>
7871 if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>,
const char *> || std::is_same_v<std::decay_t<T>,
char *>) {
7872 std::string string_value = (std::is_same_v<T, std::string>) ? value : std::string(value);
7873 auto label_it = object_string_value_registry.find(label);
7874 if (label_it != object_string_value_registry.end()) {
7875 auto value_it = label_it->second.find(string_value);
7876 if (value_it != label_it->second.end() && value_it->second > 0) {
7878 if (value_it->second == 0) {
7879 label_it->second.erase(value_it);
7880 if (label_it->second.empty()) {
7881 object_string_value_registry.erase(label_it);
7886 }
else if constexpr (std::is_same_v<T, int>) {
7887 auto label_it = object_int_value_registry.find(label);
7888 if (label_it != object_int_value_registry.end()) {
7889 auto value_it = label_it->second.find(value);
7890 if (value_it != label_it->second.end() && value_it->second > 0) {
7892 if (value_it->second == 0) {
7893 label_it->second.erase(value_it);
7894 if (label_it->second.empty()) {
7895 object_int_value_registry.erase(label_it);
7900 }
else if constexpr (std::is_same_v<T, uint>) {
7901 auto label_it = object_uint_value_registry.find(label);
7902 if (label_it != object_uint_value_registry.end()) {
7903 auto value_it = label_it->second.find(value);
7904 if (value_it != label_it->second.end() && value_it->second > 0) {
7906 if (value_it->second == 0) {
7907 label_it->second.erase(value_it);
7908 if (label_it->second.empty()) {
7909 object_uint_value_registry.erase(label_it);
7926 template<
typename T>
7928 static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>,
"getUniquePrimitiveDataValues() only supports std::string, int, and uint types.");
7931 helios_runtime_error(
"ERROR (Context::getUniquePrimitiveDataValues): Value-level caching is not enabled for primitive data label '" + label +
"'. Use enablePrimitiveDataValueCaching() first.");
7936 if constexpr (std::is_same_v<T, std::string>) {
7937 auto it = primitive_string_value_registry.find(label);
7938 if (it != primitive_string_value_registry.end()) {
7939 values.reserve(it->second.size());
7940 for (
const auto &[value, count]: it->second) {
7942 values.push_back(value);
7946 }
else if constexpr (std::is_same_v<T, int>) {
7947 auto it = primitive_int_value_registry.find(label);
7948 if (it != primitive_int_value_registry.end()) {
7949 values.reserve(it->second.size());
7950 for (
const auto &[value, count]: it->second) {
7952 values.push_back(value);
7956 }
else if constexpr (std::is_same_v<T, uint>) {
7957 auto it = primitive_uint_value_registry.find(label);
7958 if (it != primitive_uint_value_registry.end()) {
7959 values.reserve(it->second.size());
7960 for (
const auto &[value, count]: it->second) {
7962 values.push_back(value);
7976 template<
typename T>
7978 static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, uint>,
"getUniqueObjectDataValues() only supports std::string, int, and uint types.");
7981 helios_runtime_error(
"ERROR (Context::getUniqueObjectDataValues): Value-level caching is not enabled for object data label '" + label +
"'. Use enableObjectDataValueCaching() first.");
7986 if constexpr (std::is_same_v<T, std::string>) {
7987 auto it = object_string_value_registry.find(label);
7988 if (it != object_string_value_registry.end()) {
7989 values.reserve(it->second.size());
7990 for (
const auto &[value, count]: it->second) {
7992 values.push_back(value);
7996 }
else if constexpr (std::is_same_v<T, int>) {
7997 auto it = object_int_value_registry.find(label);
7998 if (it != object_int_value_registry.end()) {
7999 values.reserve(it->second.size());
8000 for (
const auto &[value, count]: it->second) {
8002 values.push_back(value);
8006 }
else if constexpr (std::is_same_v<T, uint>) {
8007 auto it = object_uint_value_registry.find(label);
8008 if (it != object_uint_value_registry.end()) {
8009 values.reserve(it->second.size());
8010 for (
const auto &[value, count]: it->second) {
8012 values.push_back(value);