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)
29#define DEPRECATED_MSG(msg, func) __declspec(deprecated) func
30#define DEPRECATED_NOMSG(func) __declspec(deprecated) func
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
38#define GET_ARG_COUNT(...) GET_ARG_COUNT_IMPL(__VA_ARGS__, 2, 1)
39#define GET_ARG_COUNT_IMPL(_1, _2, N, ...) N
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
47#define DEPRECATED_1_ARGS(func) DEPRECATED_NOMSG(func)
48#define DEPRECATED_2_ARGS(func, msg) DEPRECATED_MSG(msg, func)
52#define M_PI 3.14159265358979323846
56constexpr float PI_F = 3.14159265358979323846f;
80#include <unordered_map>
91template<
typename To,
typename From>
92constexpr To
scast(From &&v)
noexcept {
93 return static_cast<To
>(std::forward<From>(v));
100#include "pugixml.hpp"
196 void matmult(
const float ML[16],
const float MR[16],
float (&T)[16]);
204 void vecmult(
const float M[16],
const float v[3],
float (&result)[3]);
227 [[nodiscard]]
float deg2rad(
float deg);
236 [[nodiscard]]
float rad2deg(
float rad);
243 [[nodiscard]]
float atan2_2pi(
float y,
float x);
252 [[nodiscard]] SphericalCoord
cart2sphere(
const vec3 &Cartesian);
261 [[nodiscard]] vec3
sphere2cart(
const SphericalCoord &Spherical);
305 bool parse_float(
const std::string &input_string,
float &converted_float);
313 bool parse_double(
const std::string &input_string,
double &converted_double);
321 bool parse_int(
const std::string &input_string,
int &converted_int);
329 bool parse_int2(
const std::string &input_string, int2 &converted_int2);
337 bool parse_int3(
const std::string &input_string, int3 &converted_int3);
345 bool parse_uint(
const std::string &input_string,
uint &converted_uint);
353 bool parse_vec2(
const std::string &input_string, vec2 &converted_vec2);
361 bool parse_vec3(
const std::string &input_string, vec3 &converted_vec3);
369 bool parse_RGBcolor(
const std::string &input_string, RGBcolor &converted_rgb);
378 bool open_xml_file(
const std::string &xml_file, pugi::xml_document &xmldoc, std::string &error_string);
387 [[nodiscard]]
int parse_xml_tag_int(
const pugi::xml_node &node,
const std::string &tag,
const std::string &calling_function);
396 [[nodiscard]]
float parse_xml_tag_float(
const pugi::xml_node &node,
const std::string &tag,
const std::string &calling_function);
405 [[nodiscard]] vec2
parse_xml_tag_vec2(
const pugi::xml_node &node,
const std::string &tag,
const std::string &calling_function);
414 [[nodiscard]] vec3
parse_xml_tag_vec3(
const pugi::xml_node &node,
const std::string &tag,
const std::string &calling_function);
423 [[nodiscard]] std::string
parse_xml_tag_string(
const pugi::xml_node &node,
const std::string &tag,
const std::string &calling_function);
435 [[nodiscard]] std::string
deblank(
const char *input);
441 [[nodiscard]] std::string
deblank(
const std::string &input);
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.");
471 }
else if (value >
max) {
482 [[nodiscard]]
float sum(
const std::vector<float> &vect);
489 [[nodiscard]]
float mean(
const std::vector<float> &vect);
496 [[nodiscard]]
float min(
const std::vector<float> &vect);
503 [[nodiscard]]
int min(
const std::vector<int> &vect);
510 [[nodiscard]] vec3
min(
const std::vector<vec3> &vect);
517 [[nodiscard]]
float max(
const std::vector<float> &vect);
524 [[nodiscard]]
int max(
const std::vector<int> &vect);
531 [[nodiscard]] vec3
max(
const std::vector<vec3> &vect);
538 [[nodiscard]]
float stdev(
const std::vector<float> &vect);
545 [[nodiscard]]
float median(std::vector<float> vect);
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));
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)));
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))));
592 [[nodiscard]] RGBcolor blend(
const RGBcolor &color0,
const RGBcolor &color1,
float weight);
600 [[nodiscard]] RGBAcolor blend(
const RGBAcolor &color0,
const RGBAcolor &color1,
float weight);
608 [[nodiscard]] vec3
rotatePoint(
const vec3 &position,
const SphericalCoord &rotation);
617 [[nodiscard]] vec3
rotatePoint(
const vec3 &position,
float theta,
float phi);
626 [[nodiscard]] vec3 rotatePointAboutLine(
const vec3 &point,
const vec3 &line_base,
const vec3 &line_direction,
float theta);
645 [[nodiscard]] Date CalendarDay(
int Julian_day,
int year);
655 [[nodiscard]]
int JulianDay(
int day,
int month,
int year);
664 [[nodiscard]]
int JulianDay(
const Date &date);
668 [[nodiscard]]
float randu();
674 [[nodiscard]]
int randu(
int imin,
int imax);
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);
714 [[nodiscard]]
bool lineIntersection(
const vec2 &p1,
const vec2 &q1,
const vec2 &p2,
const vec2 &q2);
723 [[nodiscard]]
bool pointOnSegment(
const vec2 &point,
const vec2 &seg_start,
const vec2 &seg_end);
729 [[nodiscard]]
bool pointInPolygon(
const vec2 &point,
const std::vector<vec2> &polygon_verts);
743 timer_start = std::chrono::high_resolution_clock::now();
757 double toc(
const char *message)
const {
759 std::cerr <<
"ERROR (Timer): You must call `tic' before calling `toc'. Ignoring call to `toc'..." << std::endl;
763 auto timer_end = std::chrono::high_resolution_clock::now();
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;
774 std::chrono::high_resolution_clock::time_point timer_start;
797 ProgressBar(
size_t total,
int width = 50,
bool enable =
true,
const std::string &progress_message =
"Progress");
806 void update(
size_t step_number);
832 void wait(
float seconds);
838 [[nodiscard]]
bool PNGHasAlpha(
const char *filename);
845 [[nodiscard]] std::vector<std::vector<bool>>
readPNGAlpha(
const std::string &filename);
854 void readPNG(
const std::string &filename,
uint &width,
uint &height, std::vector<helios::RGBAcolor> &pixel_data);
863 void writePNG(
const std::string &filename,
uint width,
uint height,
const std::vector<helios::RGBAcolor> &pixel_data);
873 void writePNG(
const std::string &filename,
uint width,
uint height,
const std::vector<unsigned char> &pixel_data);
882 void readJPEG(
const std::string &filename,
uint &width,
uint &height, std::vector<helios::RGBcolor> &pixel_data);
897 void writeJPEG(
const std::string &filename,
uint width,
uint height,
const std::vector<helios::RGBcolor> &pixel_data);
907 void writeJPEG(
const std::string &filename,
uint width,
uint height,
const std::vector<unsigned char> &pixel_data);
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());
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());
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());
967 [[nodiscard]]
helios::vec3 spline_interp3(
float u,
const vec3 &x_start,
const vec3 &tan_start,
const vec3 &x_end,
const vec3 &tan_end);
974 [[nodiscard]]
float XMLloadfloat(pugi::xml_node node,
const char *field);
981 [[nodiscard]]
int XMLloadint(pugi::xml_node node,
const char *field);
988 [[nodiscard]] std::string XMLloadstring(pugi::xml_node node,
const char *field);
995 [[nodiscard]]
helios::vec2 XMLloadvec2(pugi::xml_node node,
const char *field);
1002 [[nodiscard]]
helios::vec3 XMLloadvec3(pugi::xml_node node,
const char *field);
1009 [[nodiscard]]
helios::vec4 XMLloadvec4(pugi::xml_node node,
const char *field);
1016 [[nodiscard]]
helios::int2 XMLloadint2(pugi::xml_node node,
const char *field);
1023 [[nodiscard]]
helios::int3 XMLloadint3(pugi::xml_node node,
const char *field);
1030 [[nodiscard]]
helios::int4 XMLloadint4(pugi::xml_node node,
const char *field);
1037 [[nodiscard]]
helios::RGBcolor XMLloadrgb(pugi::xml_node node,
const char *field);
1044 [[nodiscard]]
helios::RGBAcolor XMLloadrgba(pugi::xml_node node,
const char *field);
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);
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);
1077 [[nodiscard]]
float interp1(
const std::vector<helios::vec2> &points,
float x);
1095 [[nodiscard]] std::vector<float>
linspace(
float start,
float end,
int num);
1105 [[nodiscard]] std::vector<vec2>
linspace(
const vec2 &start,
const vec2 &end,
int num);
1115 [[nodiscard]] std::vector<vec3>
linspace(
const vec3 &start,
const vec3 &end,
int num);
1125 [[nodiscard]] std::vector<vec4>
linspace(
const vec4 &start,
const vec4 &end,
int num);
1143 [[nodiscard]] std::string
getFileStem(
const std::string &filepath);
1152 [[nodiscard]] std::string
getFileName(
const std::string &filepath);
1162 [[nodiscard]] std::string
getFilePath(
const std::string &filepath,
bool trailingslash =
true);
1170 [[nodiscard]]
bool validateOutputPath(std::string &output_directory,
const std::vector<std::string> &allowable_file_extensions = {});
1181 [[nodiscard]] std::filesystem::path
resolveAssetPath(
const std::string &relativePath);
1190 [[nodiscard]] std::filesystem::path
resolvePluginAsset(
const std::string &pluginName,
const std::string &assetPath);
1205 [[nodiscard]] std::filesystem::path
resolveFilePath(
const std::string &filename);
1213 [[nodiscard]] std::filesystem::path
resolveSpectraPath(
const std::string &spectraFile);
1230 [[nodiscard]] std::filesystem::path
findProjectRoot(
const std::filesystem::path &startPath = std::filesystem::current_path());
1240 [[nodiscard]] std::filesystem::path
resolveProjectFile(
const std::string &relativePath);
1247 [[nodiscard]] std::vector<float> importVectorFromFile(
const std::string &filepath);
1256 [[nodiscard]]
float sample_Beta_distribution(
float mu,
float nu, std::minstd_rand0 *generator);
1266 [[nodiscard]]
float sample_ellipsoidal_azimuth(
float e,
float phi0_degrees, std::minstd_rand0 *generator);
1268 inline std::vector<float> &operator+=(std::vector<float> &lhs,
const std::vector<float> &rhs) {
1270 if (lhs.size() != rhs.size()) {
1271 throw std::invalid_argument(
"Vector sizes must match for element-wise addition");
1275 for (
size_t i = 0; i < lhs.size(); ++i) {
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");
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];
1301 std::vector<int> coords;
1302 bool operator==(
PixelUVKey const &o)
const noexcept {
1303 return coords == o.coords;
1313 size_t operator()(
PixelUVKey const &k)
const noexcept {
1314 uint64_t h = 146527;
1315 for (
int v: k.coords) {
1317 h ^= uint64_t(v) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
1331 std::streambuf *old_buf;
1332 std::ostringstream captured_stream;
1335 old_buf = std::cerr.rdbuf(captured_stream.rdbuf());
1339 std::cerr.rdbuf(old_buf);
1344 return captured_stream.str();
1349 return !captured_stream.str().empty();
1354 captured_stream.str(
"");
1355 captured_stream.clear();
1360 return captured_stream.str().size();
1372 std::streambuf *old_buf;
1373 std::ostringstream captured_stream;
1376 old_buf = std::cout.rdbuf(captured_stream.rdbuf());
1380 std::cout.rdbuf(old_buf);
1385 return captured_stream.str();
1390 return !captured_stream.str().empty();
1395 captured_stream.str(
"");
1396 captured_stream.clear();
1401 return captured_stream.str().size();
1407 extern SphericalCoord nullrotation;
1409 extern vec3 nullorigin;