1.3.49
 
Loading...
Searching...
No Matches
global.h
Go to the documentation of this file.
1
16#ifndef HELIOS_GLOBAL
17#define HELIOS_GLOBAL
18
20// MSVC requires __declspec to come BEFORE the function declaration
21#if __cplusplus >= 201402L && defined(__has_cpp_attribute) && __has_cpp_attribute(deprecated)
22#define DEPRECATED_MSG(msg, func) [[deprecated(msg)]] func
23#define DEPRECATED_NOMSG(func) [[deprecated]] func
24#elif defined(__GNUC__) || defined(__clang__)
25#define DEPRECATED_MSG(msg, func) func __attribute__((deprecated(msg)))
26#define DEPRECATED_NOMSG(func) func __attribute__((deprecated))
27#elif defined(_MSC_VER)
28// MSVC has issues with custom deprecation messages, use simple deprecation
29#define DEPRECATED_MSG(msg, func) __declspec(deprecated) func
30#define DEPRECATED_NOMSG(func) __declspec(deprecated) func
31#else
32#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
33#define DEPRECATED_MSG(msg, func) func
34#define DEPRECATED_NOMSG(func) func
35#endif
36
37// Helper macro to count arguments
38#define GET_ARG_COUNT(...) GET_ARG_COUNT_IMPL(__VA_ARGS__, 2, 1)
39#define GET_ARG_COUNT_IMPL(_1, _2, N, ...) N
40
41// Main DEPRECATED macro that dispatches based on argument count with corrected parameter order
42#define DEPRECATED(...) GET_DEPRECATED_MACRO(__VA_ARGS__)(__VA_ARGS__)
43#define GET_DEPRECATED_MACRO(...) GET_DEPRECATED_MACRO_IMPL(GET_ARG_COUNT(__VA_ARGS__))
44#define GET_DEPRECATED_MACRO_IMPL(count) GET_DEPRECATED_MACRO_IMPL2(count)
45#define GET_DEPRECATED_MACRO_IMPL2(count) DEPRECATED_##count##_ARGS
46
47#define DEPRECATED_1_ARGS(func) DEPRECATED_NOMSG(func)
48#define DEPRECATED_2_ARGS(func, msg) DEPRECATED_MSG(msg, func)
49
51#ifndef M_PI
52#define M_PI 3.14159265358979323846
53#endif
54
56constexpr float PI_F = 3.14159265358979323846f;
57
58#include <algorithm>
59#include <array>
60#include <cassert>
61#include <chrono>
62#include <cmath>
63#include <cstdio>
64#include <cstdlib>
65#include <cstring>
66#include <ctime>
67#include <exception>
68#include <filesystem>
69#include <fstream>
70#include <iomanip>
71#include <iostream>
72#include <map>
73#include <memory>
74#include <random>
75#include <set>
76#include <sstream>
77#include <stdexcept>
78#include <thread>
79#include <type_traits>
80#include <unordered_map>
81#include <vector>
82
83#ifdef USE_OPENMP
84#include <omp.h>
85#endif
86
88typedef unsigned int uint;
89
91template<typename To, typename From>
92constexpr To scast(From &&v) noexcept {
93 return static_cast<To>(std::forward<From>(v));
94}
95
96
97#include "helios_vector_types.h"
98
99// pugi XML parser
100#include "pugixml.hpp"
101
102// Standard library for file path resolution
103#include <filesystem>
104
105// *** Groups *** //
106
108
113
118
122namespace helios {
123
125
128 void helios_runtime_error(const std::string &error_message);
129
130 //--------------------- HELPER FUNCTIONS -----------------------------------//
131
133
139 void makeRotationMatrix(float rotation, const char *axis, float (&transform)[16]);
140
142
148 void makeRotationMatrix(float rotation, const helios::vec3 &axis, float (&transform)[16]);
149
151
158 void makeRotationMatrix(float rotation, const helios::vec3 &origin, const helios::vec3 &axis, float (&transform)[16]);
159
161
166 void makeTranslationMatrix(const helios::vec3 &translation, float (&transform)[16]);
167
169
174 void makeScaleMatrix(const helios::vec3 &scale, float (&transform)[16]);
175
177
183 void makeScaleMatrix(const helios::vec3 &scale, const helios::vec3 &point, float (&transform)[16]);
184
186
196 void matmult(const float ML[16], const float MR[16], float (&T)[16]);
197
199
204 void vecmult(const float M[16], const float v[3], float (&result)[3]);
205
207
212 void vecmult(const float M[16], const helios::vec3 &v3, helios::vec3 &result);
213
215
218 void makeIdentityMatrix(float (&T)[16]);
219
221
227 [[nodiscard]] float deg2rad(float deg);
228
230
236 [[nodiscard]] float rad2deg(float rad);
237
239
243 [[nodiscard]] float atan2_2pi(float y, float x);
244
246
252 [[nodiscard]] SphericalCoord cart2sphere(const vec3 &Cartesian);
253
255
261 [[nodiscard]] vec3 sphere2cart(const SphericalCoord &Spherical);
262
264
267 [[nodiscard]] vec2 string2vec2(const char *str);
268
270
273 [[nodiscard]] vec3 string2vec3(const char *str);
274
276
279 [[nodiscard]] vec4 string2vec4(const char *str);
280
282
285 [[nodiscard]] int2 string2int2(const char *str);
286
288
291 [[nodiscard]] int3 string2int3(const char *str);
292
294
297 [[nodiscard]] int4 string2int4(const char *str);
298
300
305 bool parse_float(const std::string &input_string, float &converted_float);
306
308
313 bool parse_double(const std::string &input_string, double &converted_double);
314
316
321 bool parse_int(const std::string &input_string, int &converted_int);
322
324
329 bool parse_int2(const std::string &input_string, int2 &converted_int2);
330
332
337 bool parse_int3(const std::string &input_string, int3 &converted_int3);
338
340
345 bool parse_uint(const std::string &input_string, uint &converted_uint);
346
348
353 bool parse_vec2(const std::string &input_string, vec2 &converted_vec2);
354
356
361 bool parse_vec3(const std::string &input_string, vec3 &converted_vec3);
362
364
369 bool parse_RGBcolor(const std::string &input_string, RGBcolor &converted_rgb);
370
372
378 bool open_xml_file(const std::string &xml_file, pugi::xml_document &xmldoc, std::string &error_string);
379
381
387 [[nodiscard]] int parse_xml_tag_int(const pugi::xml_node &node, const std::string &tag, const std::string &calling_function);
388
390
396 [[nodiscard]] float parse_xml_tag_float(const pugi::xml_node &node, const std::string &tag, const std::string &calling_function);
397
399
405 [[nodiscard]] vec2 parse_xml_tag_vec2(const pugi::xml_node &node, const std::string &tag, const std::string &calling_function);
406
408
414 [[nodiscard]] vec3 parse_xml_tag_vec3(const pugi::xml_node &node, const std::string &tag, const std::string &calling_function);
415
417
423 [[nodiscard]] std::string parse_xml_tag_string(const pugi::xml_node &node, const std::string &tag, const std::string &calling_function);
424
426
429 [[nodiscard]] RGBAcolor string2RGBcolor(const char *str);
430
432
435 [[nodiscard]] std::string deblank(const char *input);
436
438
441 [[nodiscard]] std::string deblank(const std::string &input);
442
444
447 [[nodiscard]] std::string trim_whitespace(const std::string &input);
448
450
456 [[nodiscard]] std::vector<std::string> separate_string_by_delimiter(const std::string &inputstring, const std::string &delimiter);
457
459
465 template<typename anytype>
466 [[nodiscard]] anytype clamp(anytype value, anytype min, anytype max) {
467 static_assert(std::is_same_v<anytype, int> || std::is_same_v<anytype, uint> || std::is_same_v<anytype, float> || std::is_same_v<anytype, double> || std::is_same_v<anytype, char> || std::is_same_v<anytype, unsigned char>,
468 "helios::clamp() was called with an unsupported type.");
469 if (value < min) {
470 value = min;
471 } else if (value > max) {
472 value = max;
473 }
474 return value;
475 }
476
478
482 [[nodiscard]] float sum(const std::vector<float> &vect);
483
485
489 [[nodiscard]] float mean(const std::vector<float> &vect);
490
492
496 [[nodiscard]] float min(const std::vector<float> &vect);
497
499
503 [[nodiscard]] int min(const std::vector<int> &vect);
504
506
510 [[nodiscard]] vec3 min(const std::vector<vec3> &vect);
511
513
517 [[nodiscard]] float max(const std::vector<float> &vect);
518
520
524 [[nodiscard]] int max(const std::vector<int> &vect);
525
527
531 [[nodiscard]] vec3 max(const std::vector<vec3> &vect);
532
534
538 [[nodiscard]] float stdev(const std::vector<float> &vect);
539
541
545 [[nodiscard]] float median(std::vector<float> vect);
546
548
554 template<typename anytype>
555 typename std::enable_if<std::is_default_constructible<anytype>::value>::type resize_vector(std::vector<std::vector<anytype>> &vec, size_t Nx, size_t Ny) {
556 vec.assign(Ny, std::vector<anytype>(Nx));
557 }
558
560
567 template<typename anytype>
568 typename std::enable_if<std::is_default_constructible<anytype>::value>::type resize_vector(std::vector<std::vector<std::vector<anytype>>> &vec, size_t Nx, size_t Ny, size_t Nz) {
569 vec.assign(Nz, std::vector<std::vector<anytype>>(Ny, std::vector<anytype>(Nx)));
570 }
571
573
581 template<typename anytype>
582 typename std::enable_if<std::is_default_constructible<anytype>::value>::type resize_vector(std::vector<std::vector<std::vector<std::vector<anytype>>>> &vec, size_t Nx, size_t Ny, size_t Nz, size_t Nw) {
583 vec.assign(Nw, std::vector<std::vector<std::vector<anytype>>>(Nz, std::vector<std::vector<anytype>>(Ny, std::vector<anytype>(Nx))));
584 }
585
587
592 [[nodiscard]] RGBcolor blend(const RGBcolor &color0, const RGBcolor &color1, float weight);
593
595
600 [[nodiscard]] RGBAcolor blend(const RGBAcolor &color0, const RGBAcolor &color1, float weight);
601
603
608 [[nodiscard]] vec3 rotatePoint(const vec3 &position, const SphericalCoord &rotation);
609
611
617 [[nodiscard]] vec3 rotatePoint(const vec3 &position, float theta, float phi);
618
620
626 [[nodiscard]] vec3 rotatePointAboutLine(const vec3 &point, const vec3 &line_base, const vec3 &line_direction, float theta);
627
629
636 [[nodiscard]] float calculateTriangleArea(const vec3 &v0, const vec3 &v1, const vec3 &v2);
637
639
645 [[nodiscard]] Date CalendarDay(int Julian_day, int year);
646
648
655 [[nodiscard]] int JulianDay(int day, int month, int year);
656
658
664 [[nodiscard]] int JulianDay(const Date &date);
665
667
668 [[nodiscard]] float randu();
669
671
674 [[nodiscard]] int randu(int imin, int imax);
675
677
680 [[nodiscard]] float acos_safe(float x);
681
683
686 [[nodiscard]] float asin_safe(float x);
687
689
693 template<typename T>
694 T powi(T base, std::size_t exp) {
695 static_assert(std::is_same_v<T, uint> || std::is_same_v<T, int> || std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, char> || std::is_same_v<T, size_t>, "helios::powi() was called with an unsupported type.");
696 T result = static_cast<T>(1);
697 while (exp > 0) {
698 // If the low bit is set, multiply result by current base
699 if (exp & 1) {
700 result *= base;
701 }
702 // Square the base for the next bit
703 base *= base;
704 // Shift off the processed bit
705 exp >>= 1;
706 }
707 return result;
708 }
709
711
714 [[nodiscard]] bool lineIntersection(const vec2 &p1, const vec2 &q1, const vec2 &p2, const vec2 &q2);
715
717
723 [[nodiscard]] bool pointOnSegment(const vec2 &point, const vec2 &seg_start, const vec2 &seg_end);
724
726
729 [[nodiscard]] bool pointInPolygon(const vec2 &point, const std::vector<vec2> &polygon_verts);
730
732
735 struct Timer {
736 public:
737 Timer() {
738 running = false;
739 }
740
742 void tic() {
743 timer_start = std::chrono::high_resolution_clock::now();
744 running = true;
745 };
746
748 double toc() const {
749 return toc("");
750 }
751
753
757 double toc(const char *message) const {
758 if (!running) {
759 std::cerr << "ERROR (Timer): You must call `tic' before calling `toc'. Ignoring call to `toc'..." << std::endl;
760 return 0;
761 }
762
763 auto timer_end = std::chrono::high_resolution_clock::now();
764 ;
765 double duration = std::chrono::duration<double>(timer_end - timer_start).count();
766 if (strcmp(message, "mute") != 0) {
767 std::cout << "Elapsed time is " << duration << " seconds: " << message << std::endl;
768 }
769 return duration;
770 }
771
772 private:
773 bool running;
774 std::chrono::high_resolution_clock::time_point timer_start;
775 };
776
778
782 private:
783 size_t total_steps;
784 size_t current_step;
785 int bar_width;
786 bool enabled;
787 std::string message;
788
789 public:
791
797 ProgressBar(size_t total, int width = 50, bool enable = true, const std::string &progress_message = "Progress");
798
800 void update();
801
803
806 void update(size_t step_number);
807
809 void finish();
810
812
815 void setEnabled(bool enable);
816
818
821 [[nodiscard]] bool isEnabled() const;
822
825 };
826
828
832 void wait(float seconds);
833
835
838 [[nodiscard]] bool PNGHasAlpha(const char *filename);
839
841
845 [[nodiscard]] std::vector<std::vector<bool>> readPNGAlpha(const std::string &filename);
846
848
854 void readPNG(const std::string &filename, uint &width, uint &height, std::vector<helios::RGBAcolor> &pixel_data);
855
857
863 void writePNG(const std::string &filename, uint width, uint height, const std::vector<helios::RGBAcolor> &pixel_data);
864
866
873 void writePNG(const std::string &filename, uint width, uint height, const std::vector<unsigned char> &pixel_data);
874
876
882 void readJPEG(const std::string &filename, uint &width, uint &height, std::vector<helios::RGBcolor> &pixel_data);
883
885
888 [[nodiscard]] helios::int2 getImageResolutionJPEG(const std::string &filename);
889
891
897 void writeJPEG(const std::string &filename, uint width, uint height, const std::vector<helios::RGBcolor> &pixel_data);
898
900
907 void writeJPEG(const std::string &filename, uint width, uint height, const std::vector<unsigned char> &pixel_data);
908
910
914 template<typename T>
915 [[nodiscard]] std::vector<T> flatten(const std::vector<std::vector<T>> &vec) {
916 std::vector<T> result;
917 for (const auto &row: vec) {
918 result.insert(result.end(), row.begin(), row.end());
919 }
920 return result;
921 }
922
924
928 template<typename T>
929 [[nodiscard]] std::vector<T> flatten(const std::vector<std::vector<std::vector<T>>> &vec) {
930 std::vector<T> result;
931 for (const auto &matrix: vec) {
932 for (const auto &row: matrix) {
933 result.insert(result.end(), row.begin(), row.end());
934 }
935 }
936 return result;
937 }
938
940
944 template<typename T>
945 [[nodiscard]] std::vector<T> flatten(const std::vector<std::vector<std::vector<std::vector<T>>>> &vec) {
946 std::vector<T> result;
947 for (const auto &tensor: vec) {
948 for (const auto &matrix: tensor) {
949 for (const auto &row: matrix) {
950 result.insert(result.end(), row.begin(), row.end());
951 }
952 }
953 }
954 return result;
955 }
956
958
967 [[nodiscard]] helios::vec3 spline_interp3(float u, const vec3 &x_start, const vec3 &tan_start, const vec3 &x_end, const vec3 &tan_end);
968
970
974 [[nodiscard]] float XMLloadfloat(pugi::xml_node node, const char *field);
975
977
981 [[nodiscard]] int XMLloadint(pugi::xml_node node, const char *field);
982
984
988 [[nodiscard]] std::string XMLloadstring(pugi::xml_node node, const char *field);
989
991
995 [[nodiscard]] helios::vec2 XMLloadvec2(pugi::xml_node node, const char *field);
996
998
1002 [[nodiscard]] helios::vec3 XMLloadvec3(pugi::xml_node node, const char *field);
1003
1005
1009 [[nodiscard]] helios::vec4 XMLloadvec4(pugi::xml_node node, const char *field);
1010
1012
1016 [[nodiscard]] helios::int2 XMLloadint2(pugi::xml_node node, const char *field);
1017
1019
1023 [[nodiscard]] helios::int3 XMLloadint3(pugi::xml_node node, const char *field);
1024
1026
1030 [[nodiscard]] helios::int4 XMLloadint4(pugi::xml_node node, const char *field);
1031
1033
1037 [[nodiscard]] helios::RGBcolor XMLloadrgb(pugi::xml_node node, const char *field);
1038
1040
1044 [[nodiscard]] helios::RGBAcolor XMLloadrgba(pugi::xml_node node, const char *field);
1045
1047
1055 [[nodiscard]] float fzero(float (*function)(float value, std::vector<float> &variables, const void *parameters), std::vector<float> &variables, const void *parameters, float init_guess, float err_tol = 0.0001f, int max_iterations = 100);
1056
1058
1068 [[nodiscard]] float fzero(float (*function)(float value, std::vector<float> &variables, const void *parameters), std::vector<float> &variables, const void *parameters, float init_guess, bool &converged, float err_tol = 0.0001f,
1069 int max_iterations = 100);
1070
1072
1077 [[nodiscard]] float interp1(const std::vector<helios::vec2> &points, float x);
1078
1080
1085 [[nodiscard]] float point_distance(const helios::vec3 &p1, const helios::vec3 &p2);
1086
1088
1095 [[nodiscard]] std::vector<float> linspace(float start, float end, int num);
1096
1098
1105 [[nodiscard]] std::vector<vec2> linspace(const vec2 &start, const vec2 &end, int num);
1106
1108
1115 [[nodiscard]] std::vector<vec3> linspace(const vec3 &start, const vec3 &end, int num);
1116
1118
1125 [[nodiscard]] std::vector<vec4> linspace(const vec4 &start, const vec4 &end, int num);
1126
1128
1134 [[nodiscard]] std::string getFileExtension(const std::string &filepath);
1135
1137
1143 [[nodiscard]] std::string getFileStem(const std::string &filepath);
1144
1146
1152 [[nodiscard]] std::string getFileName(const std::string &filepath);
1153
1155
1162 [[nodiscard]] std::string getFilePath(const std::string &filepath, bool trailingslash = true);
1163
1165
1170 [[nodiscard]] bool validateOutputPath(std::string &output_directory, const std::vector<std::string> &allowable_file_extensions = {});
1171
1172 //--------------------- ASSET PATH RESOLUTION -----------------------------------//
1173
1175
1181 [[nodiscard]] std::filesystem::path resolveAssetPath(const std::string &relativePath);
1182
1184
1190 [[nodiscard]] std::filesystem::path resolvePluginAsset(const std::string &pluginName, const std::string &assetPath);
1191
1192
1194
1205 [[nodiscard]] std::filesystem::path resolveFilePath(const std::string &filename);
1206
1208
1213 [[nodiscard]] std::filesystem::path resolveSpectraPath(const std::string &spectraFile);
1214
1216
1221 [[nodiscard]] bool validateAssetPath(const std::filesystem::path &assetPath);
1222
1224
1230 [[nodiscard]] std::filesystem::path findProjectRoot(const std::filesystem::path &startPath = std::filesystem::current_path());
1231
1233
1240 [[nodiscard]] std::filesystem::path resolveProjectFile(const std::string &relativePath);
1241
1243
1247 [[nodiscard]] std::vector<float> importVectorFromFile(const std::string &filepath);
1248
1250
1256 [[nodiscard]] float sample_Beta_distribution(float mu, float nu, std::minstd_rand0 *generator);
1257
1266 [[nodiscard]] float sample_ellipsoidal_azimuth(float e, float phi0_degrees, std::minstd_rand0 *generator);
1267
1268 inline std::vector<float> &operator+=(std::vector<float> &lhs, const std::vector<float> &rhs) {
1269 // Make sure vectors have the same size
1270 if (lhs.size() != rhs.size()) {
1271 throw std::invalid_argument("Vector sizes must match for element-wise addition");
1272 }
1273
1274 // Perform element-by-element addition
1275 for (size_t i = 0; i < lhs.size(); ++i) {
1276 lhs[i] += rhs[i];
1277 }
1278
1279 return lhs;
1280 }
1281
1282 inline std::vector<float> operator+(const std::vector<float> &vector1, const std::vector<float> &vector2) {
1283 if (vector1.size() != vector2.size()) {
1284 throw std::invalid_argument("Vector sizes must match for element-wise addition");
1285 }
1286
1287 std::vector<float> result(vector1.size());
1288 for (std::size_t i = 0; i < vector1.size(); ++i) {
1289 result[i] = vector1[i] + vector2[i];
1290 }
1291 return result;
1292 }
1293
1300 struct PixelUVKey {
1301 std::vector<int> coords; // {x0,y0, x1,y1, …}
1302 bool operator==(PixelUVKey const &o) const noexcept {
1303 return coords == o.coords;
1304 }
1305 };
1306
1313 size_t operator()(PixelUVKey const &k) const noexcept {
1314 uint64_t h = 146527; // arbitrary seed
1315 for (int v: k.coords) {
1316 // mix in v
1317 h ^= uint64_t(v) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
1318 }
1319 return size_t(h);
1320 }
1321 };
1322
1324
1331 std::streambuf *old_buf;
1332 std::ostringstream captured_stream;
1333
1334 capture_cerr() {
1335 old_buf = std::cerr.rdbuf(captured_stream.rdbuf());
1336 }
1337
1338 ~capture_cerr() {
1339 std::cerr.rdbuf(old_buf);
1340 }
1341
1343 std::string get_captured_output() const {
1344 return captured_stream.str();
1345 }
1346
1348 bool has_output() const {
1349 return !captured_stream.str().empty();
1350 }
1351
1353 void clear() {
1354 captured_stream.str("");
1355 captured_stream.clear();
1356 }
1357
1359 size_t size() const {
1360 return captured_stream.str().size();
1361 }
1362 };
1363
1365
1372 std::streambuf *old_buf;
1373 std::ostringstream captured_stream;
1374
1375 capture_cout() {
1376 old_buf = std::cout.rdbuf(captured_stream.rdbuf());
1377 }
1378
1379 ~capture_cout() {
1380 std::cout.rdbuf(old_buf);
1381 }
1382
1384 std::string get_captured_output() const {
1385 return captured_stream.str();
1386 }
1387
1389 bool has_output() const {
1390 return !captured_stream.str().empty();
1391 }
1392
1394 void clear() {
1395 captured_stream.str("");
1396 captured_stream.clear();
1397 }
1398
1400 size_t size() const {
1401 return captured_stream.str().size();
1402 }
1403 };
1404
1405
1407 extern SphericalCoord nullrotation;
1409 extern vec3 nullorigin;
1410} // namespace helios
1411
1412#endif