2020-11-27 11:47:21 +01:00
|
|
|
#ifndef UTILITIES_H
|
|
|
|
#define UTILITIES_H
|
|
|
|
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
#include <filesystem>
|
|
|
|
#include <fstream>
|
|
|
|
#include <regex>
|
|
|
|
|
|
|
|
namespace Utilities {
|
|
|
|
inline void parseIntegers(const std::string &str, std::vector<size_t> &result) {
|
|
|
|
typedef std::regex_iterator<std::string::const_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]); });
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
//}
|
|
|
|
|
|
|
|
} // namespace Utilities
|
|
|
|
|
|
|
|
struct NodalForce {
|
|
|
|
size_t index;
|
|
|
|
size_t dof;
|
|
|
|
double magnitude;
|
|
|
|
};
|
|
|
|
struct Vector6d : public std::array<double, 6> {
|
|
|
|
Vector6d() {
|
|
|
|
for (size_t i = 0; i < 6; i++) {
|
|
|
|
this->operator[](i) = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector6d(const double &d) {
|
|
|
|
for (size_t i = 0; i < 6; i++) {
|
|
|
|
this->operator[](i) = d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector6d(const std::initializer_list<double> &initList) {
|
|
|
|
std::copy(initList.begin(), initList.end(), this->begin());
|
|
|
|
}
|
|
|
|
|
|
|
|
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 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(begin(), end(),
|
|
|
|
[&](const double &v) { squaredNorm += pow(v, 2); });
|
|
|
|
return squaredNorm;
|
|
|
|
}
|
|
|
|
|
|
|
|
double norm() const { return sqrt(squaredNorm()); }
|
|
|
|
|
|
|
|
bool isFinite() const {
|
|
|
|
return std::any_of(begin(), end(), [](const double &v) {
|
|
|
|
if (!std::isfinite(v)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// namespace ConfigurationFile {
|
|
|
|
|
|
|
|
// inline void getPlyFilename(const std::string jsonFilepath,
|
|
|
|
// std::string &plyFilename) {
|
|
|
|
// std::ifstream inFile(jsonFilepath);
|
|
|
|
// std::string jsonContents((std::istreambuf_iterator<char>(inFile)),
|
|
|
|
// std::istreambuf_iterator<char>());
|
|
|
|
// nlohmann::json jsonFile(nlohmann::json::parse(jsonContents));
|
|
|
|
|
|
|
|
// if (jsonFile.contains("plyFilename")) {
|
|
|
|
// plyFilename = jsonFile["plyFilename"];
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
// inline void
|
|
|
|
// getNodalForces(const std::string jsonFilepath,
|
|
|
|
// std::unordered_map<size_t, Eigen::Vector3d> &nodalForces) {
|
|
|
|
// std::ifstream inFile(jsonFilepath);
|
|
|
|
// std::string jsonContents((std::istreambuf_iterator<char>(inFile)),
|
|
|
|
// std::istreambuf_iterator<char>());
|
|
|
|
// nlohmann::json jsonFile(nlohmann::json::parse(jsonContents));
|
|
|
|
|
|
|
|
// nodalForces.clear();
|
|
|
|
// if (jsonFile.contains("forces")) {
|
|
|
|
// std::vector<std::vector<double>> forces = jsonFile["forces"];
|
|
|
|
// for (size_t forceIndex = 0; forceIndex < forces.size(); forceIndex++) {
|
|
|
|
// const BeamFormFinder::NodalForce nf{
|
|
|
|
// static_cast<size_t>(forces[forceIndex][0]),
|
|
|
|
// static_cast<size_t>(forces[forceIndex][1]), forces[forceIndex][2]};
|
|
|
|
// const size_t vertexIndex = forces[forceIndex][0];
|
|
|
|
// const Eigen::Vector3d forceVector(
|
|
|
|
// forces[forceIndex][1], forces[forceIndex][2],
|
|
|
|
// forces[forceIndex][3]);
|
|
|
|
// assert(forceIndex >= 0 && forceVector.norm() >= 0);
|
|
|
|
// nodalForces[vertexIndex] = forceVector;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
// inline void getFixedVertices(const std::string jsonFilepath,
|
|
|
|
// std::vector<size_t> &fixedVertices) {
|
|
|
|
// std::ifstream inFile(jsonFilepath);
|
|
|
|
// std::string jsonContents((std::istreambuf_iterator<char>(inFile)),
|
|
|
|
// std::istreambuf_iterator<char>());
|
|
|
|
// nlohmann::json jsonFile(nlohmann::json::parse(jsonContents));
|
|
|
|
|
|
|
|
// fixedVertices.clear();
|
|
|
|
// if (jsonFile.contains("fixedVertices")) {
|
|
|
|
// fixedVertices =
|
|
|
|
// static_cast<std::vector<size_t>>(jsonFile["fixedVertices"]);
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
// struct SimulationScenario {
|
|
|
|
// std::string edgeMeshFilename;
|
|
|
|
// std::vector<size_t> fixedVertices;
|
|
|
|
// std::unordered_map<size_t, Eigen::Vector3d> nodalForces;
|
|
|
|
//};
|
|
|
|
|
|
|
|
// void to_json(nlohmann::json &json, const SimulationScenario &scenario) {
|
|
|
|
// json["plyFilename"] = scenario.edgeMeshFilename;
|
|
|
|
// if (!scenario.fixedVertices.empty()) {
|
|
|
|
// json["fixedVertices"] = scenario.fixedVertices;
|
|
|
|
// }
|
|
|
|
// if (!scenario.nodalForces.empty()) {
|
|
|
|
// std::vector<std::tuple<size_t, double, double, double>> forces;
|
|
|
|
// std::transform(scenario.nodalForces.begin(), scenario.nodalForces.end(),
|
|
|
|
// std::back_inserter(forces),
|
|
|
|
// [](const std::pair<size_t, Eigen::Vector3d> &f) {
|
|
|
|
// return std::tuple<size_t, double, double, double>{
|
|
|
|
// f.first, f.second[0], f.second[1], f.second[2]};
|
|
|
|
// });
|
|
|
|
// json["forces"] = forces;
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//} // namespace ConfigurationFile
|
|
|
|
#include "polyscope/curve_network.h"
|
|
|
|
#include "polyscope/polyscope.h"
|
|
|
|
|
|
|
|
inline void initPolyscope() {
|
|
|
|
if (polyscope::state::initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
polyscope::init();
|
|
|
|
polyscope::options::groundPlaneEnabled = false;
|
|
|
|
polyscope::view::upDir = polyscope::view::UpDir::ZUp;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void registerWorldAxes() {
|
|
|
|
if (!polyscope::state::initialized) {
|
|
|
|
initPolyscope();
|
|
|
|
}
|
2020-12-09 16:59:18 +01:00
|
|
|
|
2020-11-27 11:47:21 +01:00
|
|
|
Eigen::MatrixX3d axesPositions(4, 3);
|
|
|
|
axesPositions.row(0) = Eigen::Vector3d(0, 0, 0);
|
2020-12-09 16:59:18 +01:00
|
|
|
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);
|
|
|
|
|
2020-11-27 11:47:21 +01:00
|
|
|
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.001);
|
|
|
|
const std::string worldAxesColorName = worldAxesName + " Color";
|
|
|
|
polyscope::getCurveNetwork(worldAxesName)
|
|
|
|
->addEdgeColorQuantity(worldAxesColorName, axesColors)
|
|
|
|
->setEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T1, typename T2>
|
|
|
|
void constructInverseMap(const T1 &map, T2 &oppositeMap) {
|
|
|
|
assert(!map.empty());
|
|
|
|
oppositeMap.clear();
|
|
|
|
for (const auto &mapIt : map) {
|
|
|
|
oppositeMap[mapIt.second] = mapIt.first;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // UTILITIES_H
|