#ifndef UTILITIES_H #define UTILITIES_H #include #include #include #include #include #include #include #include #include #define GET_VARIABLE_NAME(Variable) (#Variable) struct Vector6d : public std::array { Vector6d() { for (size_t i = 0; i < 6; i++) { this->operator[](i) = 0; } } Vector6d(const std::vector &v) { assert(v.size() == 6); std::copy(v.begin(), v.end(), this->begin()); } Vector6d(const double &d) { for (size_t i = 0; i < 6; i++) { this->operator[](i) = d; } } Vector6d(const std::array &arr) : std::array(arr) {} Vector6d(const std::initializer_list &initList) { std::copy(initList.begin(), initList.end(), std::begin(*this)); } Vector6d operator*(const double &d) const { Vector6d result; for (size_t i = 0; i < 6; i++) { result[i] = this->operator[](i) * d; } return result; } Vector6d operator*(const Vector6d &v) const { Vector6d result; for (size_t i = 0; i < 6; i++) { result[i] = this->operator[](i) * v[i]; } return result; } Vector6d operator/(const double &d) const { Vector6d result; for (size_t i = 0; i < 6; i++) { result[i] = this->operator[](i) / d; } return result; } Vector6d operator/(const Vector6d &v) const { Vector6d result; for (size_t i = 0; i < 6; i++) { result[i] = this->operator[](i) / v[i]; } return result; } Vector6d operator+(const Vector6d &v) const { Vector6d result; for (size_t i = 0; i < 6; i++) { result[i] = this->operator[](i) + v[i]; } return result; } Vector6d operator-(const Vector6d &v) const { Vector6d result; for (size_t i = 0; i < 6; i++) { result[i] = this->operator[](i) - v[i]; } return result; } Vector6d inverted() const { Vector6d result; for (size_t i = 0; i < 6; i++) { assert(this->operator[](i) != 0); result[i] = 1 / this->operator[](i); } return result; } bool isZero() const { for (size_t i = 0; i < 6; i++) { if (this->operator[](i) != 0) return false; } return true; } double squaredNorm() const { double squaredNorm = 0; std::for_each(this->begin(), std::end(*this), [&](const double &v) { squaredNorm += pow(v, 2); }); return squaredNorm; } double norm() const { return sqrt(squaredNorm()); } bool isFinite() const { return std::any_of(std::begin(*this), std::end(*this), [](const double &v) { if (!std::isfinite(v)) { return false; } return true; }); } Eigen::Vector3d getTranslation() const { return Eigen::Vector3d(this->operator[](0), this->operator[](1), this->operator[](2)); } Eigen::Vector3d getRotation() const { return Eigen::Vector3d(this->operator[](3), this->operator[](4), this->operator[](5)); } std::string toString() const { std::string s; for (int i = 0; i < 6; i++) { s.append(std::to_string(this->operator[](i)) + ","); } s.pop_back(); return s; } }; namespace Utilities { inline bool compareNat(const std::string &a, const std::string &b) { if (a.empty()) return true; if (b.empty()) return false; if (std::isdigit(a[0]) && !std::isdigit(b[0])) return true; if (!std::isdigit(a[0]) && std::isdigit(b[0])) return false; if (!std::isdigit(a[0]) && !std::isdigit(b[0])) { if (std::toupper(a[0]) == std::toupper(b[0])) return compareNat(a.substr(1), b.substr(1)); return (std::toupper(a[0]) < std::toupper(b[0])); } // Both strings begin with digit --> parse both numbers std::istringstream issa(a); std::istringstream issb(b); int ia, ib; issa >> ia; issb >> ib; if (ia != ib) return ia < ib; // Numbers are the same --> remove numbers and recurse std::string anew, bnew; std::getline(issa, anew); std::getline(issb, bnew); return (compareNat(anew, bnew)); } inline std::string_view leftTrimSpaces(const std::string_view& str) { std::string_view trimmedString=str; const auto pos(str.find_first_not_of(" \t\n\r\f\v")); trimmedString.remove_prefix(std::min(pos, trimmedString.length())); return trimmedString; } inline std::string_view rightTrimSpaces(const std::string_view& str) { std::string_view trimmedString=str; const auto pos(trimmedString.find_last_not_of(" \t\n\r\f\v")); trimmedString.remove_suffix(std::min(trimmedString.length() - pos - 1,trimmedString.length())); return trimmedString; } inline std::string_view trimLeftAndRightSpaces(std::string_view str) { std::string_view trimmedString=str; trimmedString = leftTrimSpaces(trimmedString); trimmedString = rightTrimSpaces(trimmedString); return trimmedString; } template inline void normalize(InputIt itBegin, InputIt itEnd) { const auto squaredSumOfElements = std::accumulate(itBegin, itEnd, 0.0, [](const auto &sum, const auto &el) { return sum + el * el; }); assert(squaredSumOfElements != 0); std::transform(itBegin, itEnd, itBegin, [&](auto &element) { return element / std::sqrt(squaredSumOfElements); }); } inline std::vector split(const std::string& text, std::string delim) { std::vector vec; size_t pos = 0, prevPos = 0; while (1) { pos = text.find(delim, prevPos); if (pos == std::string::npos) { vec.push_back(text.substr(prevPos)); return vec; } vec.push_back(text.substr(prevPos, pos - prevPos)); prevPos = pos + delim.length(); } } inline std::string toString(const std::vector> &vv) { std::string s; s.append("{"); for (const std::vector &v : vv) { s.append("{"); for (const int &i : v) { s.append(std::to_string(i) + ","); } s.pop_back(); s.append("}"); } s.append("}"); return s; } inline void parseIntegers(const std::string &str, std::vector &result) { typedef std::regex_iterator re_iterator; typedef re_iterator::value_type re_iterated; std::regex re("(\\d+)"); re_iterator rit(str.begin(), str.end(), re); re_iterator rend; std::transform(rit, rend, std::back_inserter(result), [](const re_iterated &it) { return std::stoi(it[1]); }); } inline Eigen::MatrixXd toEigenMatrix(const std::vector &v) { Eigen::MatrixXd m(v.size(), 6); for (size_t vi = 0; vi < v.size(); vi++) { const Vector6d &vec = v[vi]; for (size_t i = 0; i < 6; i++) { m(vi, i) = vec[i]; } } return m; } inline std::vector fromEigenMatrix(const Eigen::MatrixXd &m) { std::vector v(m.rows()); for (size_t vi = 0; vi < m.rows(); vi++) { const Eigen::RowVectorXd &row = m.row(vi); for (size_t i = 0; i < 6; i++) { v[vi][i] = row(i); } } return v; } // std::string convertToLowercase(const std::string &s) { // std::string lowercase; // std::transform(s.begin(), s.end(), lowercase.begin(), // [](unsigned char c) { return std::tolower(c); }); // return lowercase; //} // bool hasExtension(const std::string &filename, const std::string &extension) // { // const std::filesystem::path path(filename); // if (!path.has_extension()) { // std::cerr << "Error: No file extension found in " << filename << // std::endl; return false; // } // const std::string detectedExtension = path.extension().string(); // if (convertToLowercase(detectedExtension) != convertToLowercase(extension)) // { // std::cerr << "Error: detected extension is " + detectedExtension + // " and not " + extension // << std::endl; // return false; // } // return true; //} inline std::filesystem::path getFilepathWithExtension(const std::filesystem::path &folderPath, const std::string &extension) { for (const std::filesystem::directory_entry &dirEntry : std::filesystem::directory_iterator(folderPath)) { if (dirEntry.is_regular_file() && std::filesystem::path(dirEntry).extension() == extension) { return std::filesystem::path(dirEntry); } } return ""; } } // namespace Utilities #ifdef POLYSCOPE_DEFINED #include "polyscope/curve_network.h" #include "polyscope/pick.h" #include "polyscope/polyscope.h" #include namespace PolyscopeInterface { inline struct GlobalPolyscopeData { std::vector> userCallbacks; } globalPolyscopeData; inline void mainCallback() { ImGui::PushItemWidth(100); // Make ui elements 100 pixels wide, // instead of full width. Must have // matching PopItemWidth() below. for (std::function &userCallback : globalPolyscopeData.userCallbacks) { userCallback(); } ImGui::PopItemWidth(); } inline void addUserCallback(const std::function &userCallback) { globalPolyscopeData.userCallbacks.push_back(userCallback); } inline void deinitPolyscope() { if (!polyscope::state::initialized) { return; } polyscope::render::engine->shutdownImGui(); } inline void init() { if (polyscope::state::initialized) { return; } polyscope::init(); polyscope::options::groundPlaneEnabled = false; polyscope::view::upDir = polyscope::view::UpDir::ZUp; polyscope::state::userCallback = &mainCallback; polyscope::options::autocenterStructures = false; polyscope::options::autoscaleStructures = false; } using PolyscopeLabel = std::string; inline std::pair getSelection() { std::pair selection = polyscope::pick::getSelection(); if (selection.first == nullptr) { return std::make_pair(std::string(), 0); } return std::make_pair(selection.first->name, selection.second); } inline void registerWorldAxes() { PolyscopeInterface::init(); Eigen::MatrixX3d axesPositions(4, 3); axesPositions.row(0) = Eigen::Vector3d(0, 0, 0); // axesPositions.row(1) = Eigen::Vector3d(polyscope::state::lengthScale, 0, 0); // axesPositions.row(2) = Eigen::Vector3d(0, polyscope::state::lengthScale, 0); // axesPositions.row(3) = Eigen::Vector3d(0, 0, polyscope::state::lengthScale); axesPositions.row(1) = Eigen::Vector3d(1, 0, 0); axesPositions.row(2) = Eigen::Vector3d(0, 1, 0); axesPositions.row(3) = Eigen::Vector3d(0, 0, 1); Eigen::MatrixX2i axesEdges(3, 2); axesEdges.row(0) = Eigen::Vector2i(0, 1); axesEdges.row(1) = Eigen::Vector2i(0, 2); axesEdges.row(2) = Eigen::Vector2i(0, 3); Eigen::MatrixX3d axesColors(3, 3); axesColors.row(0) = Eigen::Vector3d(1, 0, 0); axesColors.row(1) = Eigen::Vector3d(0, 1, 0); axesColors.row(2) = Eigen::Vector3d(0, 0, 1); const std::string worldAxesName = "World Axes"; polyscope::registerCurveNetwork(worldAxesName, axesPositions, axesEdges); polyscope::getCurveNetwork(worldAxesName)->setRadius(0.0001, false); const std::string worldAxesColorName = worldAxesName + " Color"; polyscope::getCurveNetwork(worldAxesName) ->addEdgeColorQuantity(worldAxesColorName, axesColors) ->setEnabled(true); } } // namespace PolyscopeInterface #endif // namespace ConfigurationFile { //} //} // namespace ConfigurationFile template void constructInverseMap(const T1 &map, T2 &oppositeMap) { assert(!map.empty()); oppositeMap.clear(); for (const auto &mapIt : map) { oppositeMap[mapIt.second] = mapIt.first; } } template std::string toString(const T &v) { return "(" + std::to_string(v[0]) + "," + std::to_string(v[1]) + "," + std::to_string(v[2]) + ")"; } template std::string to_string_with_precision(const T a_value, const int n = 2) { std::ostringstream out; out.precision(n); out << std::fixed << a_value; return out.str(); } template size_t computeHashUnordered(const std::vector &v) { size_t hash = 0; for (const auto &el : v) { hash += std::hash{}(el); } return hash; } inline size_t computeHashOrdered(const std::vector &v) { std::string elementsString; for (const auto &el : v) { elementsString += std::to_string(el); } return std::hash{}(elementsString); } #endif // UTILITIES_H