Moved files to DRMSimulationModel project
This commit is contained in:
parent
90551e5485
commit
7780e4ab38
152
CMakeLists.txt
152
CMakeLists.txt
|
@ -2,11 +2,12 @@ cmake_minimum_required(VERSION 3.0)
|
|||
project(MySources)
|
||||
|
||||
file(GLOB MySourcesFiles ${CMAKE_CURRENT_LIST_DIR}/*.hpp ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
|
||||
add_library(${PROJECT_NAME} STATIC ${MySourcesFiles} )
|
||||
add_library(${PROJECT_NAME} ${MySourcesFiles} )
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
|
||||
|
||||
#Download external dependencies NOTE: If the user has one of these libs it shouldn't be downloaded again.
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/DownloadProject.cmake)
|
||||
include(FetchContent)
|
||||
if (CMAKE_VERSION VERSION_LESS 3.2)
|
||||
set(UPDATE_DISCONNECTED_IF_AVAILABLE "")
|
||||
else()
|
||||
|
@ -19,6 +20,13 @@ endif()
|
|||
##Create directory for the external libraries
|
||||
file(MAKE_DIRECTORY ${EXTERNAL_DEPS_DIR})
|
||||
|
||||
set(DRMSimulationModelDir "/home/iason/Coding/Libraries/DRMSimulationModel")
|
||||
message("drm dir:" ${DRMSimulationModelDir})
|
||||
add_subdirectory(${DRMSimulationModelDir} "/home/iason/Coding/build/DRMSimulationModel")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC DRMSimulationModel)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${DRMSimulationModelDir})
|
||||
|
||||
#target_sources(${PROJECT_NAME} PUBLIC ${DRMSimulationModelDir}/simulationmodel.hpp)
|
||||
##dlib
|
||||
#set(DLIB_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/dlib)
|
||||
#download_project(PROJ DLIB
|
||||
|
@ -36,56 +44,77 @@ file(MAKE_DIRECTORY ${EXTERNAL_DEPS_DIR})
|
|||
#endif()
|
||||
#add_compile_definitions(DLIB_DEFINED)
|
||||
|
||||
if(${USE_POLYSCOPE})
|
||||
set(POLYSCOPE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/polyscope)
|
||||
download_project(PROJ POLYSCOPE
|
||||
## polyscope
|
||||
FetchContent_Declare(polyscope
|
||||
GIT_REPOSITORY https://github.com/nmwsharp/polyscope.git
|
||||
GIT_TAG master
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
BINARY_DIR ${POLYSCOPE_BINARY_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${POLYSCOPE_SOURCE_DIR} ${POLYSCOPE_BINARY_DIR})
|
||||
add_compile_definitions(POLYSCOPE_DEFINED)
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${POLYSCOPE_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.cpp)
|
||||
FetchContent_MakeAvailable(polyscope)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${polyscope_SOURCE_DIR}/include)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC polyscope)
|
||||
#if(NOT TARGET polyscope AND ${USE_POLYSCOPE})
|
||||
# set(POLYSCOPE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/polyscope)
|
||||
# download_project(PROJ POLYSCOPE
|
||||
# GIT_REPOSITORY https://github.com/nmwsharp/polyscope.git
|
||||
# GIT_TAG master
|
||||
# PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
# BINARY_DIR ${POLYSCOPE_BINARY_DIR}
|
||||
# ${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
# )
|
||||
# add_subdirectory(${POLYSCOPE_SOURCE_DIR} ${POLYSCOPE_BINARY_DIR})
|
||||
# add_compile_definitions(POLYSCOPE_DEFINED)
|
||||
# target_sources(${PROJECT_NAME} PUBLIC ${POLYSCOPE_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.cpp)
|
||||
|
||||
message("Using polyscope..")
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${POLYSCOPE_SOURCE_DIR}/include)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC polyscope)
|
||||
endif()
|
||||
# message("Using polyscope..")
|
||||
# target_include_directories(${PROJECT_NAME} PUBLIC ${POLYSCOPE_SOURCE_DIR}/include)
|
||||
# target_link_libraries(${PROJECT_NAME} PUBLIC polyscope)
|
||||
#endif()
|
||||
|
||||
##vcglib devel branch
|
||||
download_project(PROJ vcglib_devel
|
||||
FetchContent_Declare(vcglib
|
||||
GIT_REPOSITORY https://gitea-s2i2s.isti.cnr.it/manolas/vcglib.git
|
||||
GIT_TAG devel
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${vcglib_devel_SOURCE_DIR} ${vcglib_devel_BINARY_DIR})
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${vcglib_devel_SOURCE_DIR}/wrap/ply/plylib.cpp)
|
||||
)
|
||||
FetchContent_MakeAvailable(vcglib)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${vcglib_SOURCE_DIR})
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${vcglib_SOURCE_DIR}/wrap/ply/plylib.cpp)
|
||||
|
||||
##matplot++ lib
|
||||
set(MATPLOTPLUSPLUS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/matplot)
|
||||
download_project(PROJ MATPLOTPLUSPLUS
|
||||
###matplot++ lib
|
||||
FetchContent_Declare(matplot
|
||||
GIT_REPOSITORY https://github.com/alandefreitas/matplotplusplus
|
||||
GIT_TAG master
|
||||
BINARY_DIR ${MATPLOTPLUSPLUS_BINARY_DIR}
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${MATPLOTPLUSPLUS_SOURCE_DIR} ${MATPLOTPLUSPLUS_BINARY_DIR})
|
||||
FetchContent_MakeAvailable(matplot)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${matplot_SOURCE_DIR})
|
||||
#set(MATPLOTPLUSPLUS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/matplot)
|
||||
#download_project(PROJ MATPLOTPLUSPLUS
|
||||
# GIT_TAG master
|
||||
# BINARY_DIR ${MATPLOTPLUSPLUS_BINARY_DIR}
|
||||
# PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
# ${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
# )
|
||||
#add_subdirectory(${MATPLOTPLUSPLUS_SOURCE_DIR} ${MATPLOTPLUSPLUS_BINARY_DIR})
|
||||
|
||||
##threed-beam-fea
|
||||
set(threed-beam-fea_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/threed-beam-fea)
|
||||
download_project(PROJ threed-beam-fea
|
||||
# GIT_REPOSITORY https://github.com/IasonManolas/threed-beam-fea.git
|
||||
if(NOT TARGET ThreedBeamFEA)
|
||||
FetchContent_Declare(threed-beam-fea
|
||||
GIT_REPOSITORY https://gitea-s2i2s.isti.cnr.it/manolas/threed-beam-fea.git
|
||||
GIT_TAG master
|
||||
BINARY_DIR ${threed-beam-fea_BINARY_DIR}
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${threed-beam-fea_SOURCE_DIR} ${threed-beam-fea_BINARY_DIR})
|
||||
)
|
||||
FetchContent_MakeAvailable(threed-beam-fea)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ThreedBeamFEA)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${threed-beam-fea_SOURCE_DIR})
|
||||
|
||||
#set(threed-beam-fea_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/threed-beam-fea)
|
||||
#download_project(PROJ threed-beam-fea
|
||||
## GIT_REPOSITORY https://github.com/IasonManolas/threed-beam-fea.git
|
||||
# GIT_TAG master
|
||||
# BINARY_DIR ${threed-beam-fea_BINARY_DIR}
|
||||
# PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
# ${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
#)
|
||||
#add_subdirectory(${threed-beam-fea_SOURCE_DIR} ${threed-beam-fea_BINARY_DIR})
|
||||
|
||||
find_package(Eigen3 3.4 REQUIRED)
|
||||
if(MSVC)
|
||||
|
@ -97,17 +126,16 @@ if(${MYSOURCES_STATIC_LINK})
|
|||
endif()
|
||||
if(${MYSOURCES_STATIC_LINK})
|
||||
message("Linking statically here")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -static Eigen3::Eigen matplot ThreedBeamFEA pthread gfortran quadmath)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -static Eigen3::Eigen matplot pthread gfortran quadmath)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen matplot ThreedBeamFEA tbb pthread)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen matplot tbb pthread)
|
||||
endif()
|
||||
|
||||
target_link_directories(MySources PUBLIC ${CMAKE_CURRENT_LIST_DIR}/boost_graph/libs)
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/boost_graph
|
||||
PUBLIC ${vcglib_devel_SOURCE_DIR}
|
||||
PUBLIC ${threed-beam-fea_SOURCE_DIR}
|
||||
PUBLIC ${MATPLOTPLUSPLUS_SOURCE_DIR}/source
|
||||
# PUBLIC ${threed-beam-fea_SOURCE_DIR}
|
||||
)
|
||||
|
||||
|
||||
|
@ -118,10 +146,29 @@ add_subdirectory(${ARMADILLO_SOURCE_DIR} ${ARMADILLO_BIN_DIR})
|
|||
target_include_directories(${PROJECT_NAME} PUBLIC ${ARMADILLO_SOURCE_DIR}/include)
|
||||
add_compile_definitions(ARMA_DONT_USE_WRAPPER)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/armadillo/build/libarmadillo.a" #[[blas lapack]])
|
||||
find_package(Armadillo REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${ARMADILLO_LIBRARIES})
|
||||
#if(NOT TARGET ThreedBeamFEA)
|
||||
#FetchContent_Declare(armadillo
|
||||
# GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git
|
||||
# GIT_TAG "11.2.x"
|
||||
# )
|
||||
#FetchContent_MakeAvailable(armadillo)
|
||||
#find_package(Armadillo REQUIRED)
|
||||
#target_link_libraries(${PROJECT_NAME} PUBLIC ${ARMADILLO_LIBRARIES})
|
||||
#endif()
|
||||
#target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/build/FormFInder/Debug/_deps/armadillo-build/libarmadillo.a")
|
||||
|
||||
###ENSMALLEN
|
||||
#FetchContent_Declare(ensmallen
|
||||
# GIT_REPOSITORY https://github.com/mlpack/ensmallen.git
|
||||
# GIT_TAG master
|
||||
# )
|
||||
#FetchContent_MakeAvailable(ensmallen)
|
||||
#target_link_libraries(${PROJECT_NAME} PRIVATE ensmallen)
|
||||
#target_include_directories(${PROJECT_NAME}
|
||||
#PUBLIC ${ensmallen_SOURCE_DIR}/include)
|
||||
#add_compile_definitions(USE_ENSMALLEN)
|
||||
|
||||
##ENSMALLEN
|
||||
set(ENSMALLEN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/ensmallen)
|
||||
download_project(PROJ ENSMALLEN
|
||||
GIT_REPOSITORY https://github.com/mlpack/ensmallen.git
|
||||
|
@ -190,16 +237,21 @@ target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/chron
|
|||
|
||||
##TBB
|
||||
if(NOT TARGET tbb_static AND NOT TARGET tbb)
|
||||
set(TBB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/tbb)
|
||||
download_project(PROJ TBB
|
||||
# set(TBB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/tbb)
|
||||
# download_project(PROJ TBB
|
||||
# GIT_REPOSITORY https://github.com/wjakob/tbb.git
|
||||
# GIT_TAG master
|
||||
# PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
# BINARY_DIR ${TBB_BINARY_DIR}
|
||||
# ${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
# )
|
||||
# option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" OFF)
|
||||
# add_subdirectory(${TBB_SOURCE_DIR} ${TBB_BINARY_DIR})
|
||||
#link_directories(${TBB_BINARY_DIR})
|
||||
FetchContent_Declare(tbb
|
||||
GIT_REPOSITORY https://github.com/wjakob/tbb.git
|
||||
GIT_TAG master
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
BINARY_DIR ${TBB_BINARY_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" OFF)
|
||||
add_subdirectory(${TBB_SOURCE_DIR} ${TBB_BINARY_DIR})
|
||||
link_directories(${TBB_BINARY_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE tbb_static)
|
||||
FetchContent_MakeAvailable(tbb)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE tbb_static)
|
||||
endif()
|
||||
|
|
157
beam.hpp
157
beam.hpp
|
@ -1,157 +0,0 @@
|
|||
#ifndef BEAM_HPP
|
||||
#define BEAM_HPP
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
struct BeamDimensions
|
||||
{
|
||||
double dim1, dim2;
|
||||
double A{0}; // cross sectional area
|
||||
|
||||
struct MomentsOfInertia
|
||||
{
|
||||
double I2{0}; // second moment of inertia
|
||||
double I3{0}; // third moment of inertia
|
||||
double J{0}; // torsional constant (polar moment of inertia)
|
||||
} inertia;
|
||||
|
||||
public:
|
||||
double getDim1() const;
|
||||
double getDim2() const;
|
||||
|
||||
virtual void to_json(nlohmann::json &j, const BeamDimensions &beamDim) const;
|
||||
|
||||
virtual void from_json(const nlohmann::json &j, BeamDimensions &beamDim) const;
|
||||
virtual double getDrawingRadius() const = 0;
|
||||
};
|
||||
|
||||
inline double BeamDimensions::getDim2() const
|
||||
{
|
||||
return dim2;
|
||||
}
|
||||
|
||||
inline void BeamDimensions::to_json(nlohmann::json &j, const BeamDimensions &beamDim) const
|
||||
{
|
||||
j = nlohmann::json{{"BeamDimension.dim1", beamDim.dim1}, {"BeamDimension.dim2", beamDim.dim2}};
|
||||
}
|
||||
|
||||
inline void BeamDimensions::from_json(const nlohmann::json &j, BeamDimensions &beamDim) const
|
||||
{
|
||||
const std::string jsonKey_dim1 = "BeamDimension.dim1";
|
||||
const std::string jsonKey_dim2 = "BeamDimension.dim2";
|
||||
if (j.contains(jsonKey_dim1)) {
|
||||
j.at(jsonKey_dim1).get_to(beamDim.dim1);
|
||||
}
|
||||
if (j.contains(jsonKey_dim2)) {
|
||||
j.at(jsonKey_dim2).get_to(beamDim.dim2);
|
||||
}
|
||||
}
|
||||
|
||||
inline double BeamDimensions::getDim1() const
|
||||
{
|
||||
return dim1;
|
||||
}
|
||||
|
||||
struct RectangularBeamDimensions : public BeamDimensions
|
||||
{
|
||||
inline static std::string name{"Rectangular"};
|
||||
inline const static double defaultSize = 0.002;
|
||||
|
||||
RectangularBeamDimensions(const double &width, const double &height)
|
||||
{
|
||||
assert(width > 0 && height > 0);
|
||||
dim1 = width;
|
||||
dim2 = height;
|
||||
updateProperties();
|
||||
}
|
||||
RectangularBeamDimensions()
|
||||
{
|
||||
dim1 = defaultSize;
|
||||
dim2 = defaultSize;
|
||||
updateProperties();
|
||||
}
|
||||
|
||||
std::string toString() const
|
||||
{
|
||||
return std::string("w=") + std::to_string(dim1) + std::string(" h=") + std::to_string(dim2);
|
||||
}
|
||||
|
||||
void updateProperties()
|
||||
{
|
||||
A = dim1 * dim2;
|
||||
inertia.I2 = dim1 * std::pow(dim2, 3) / 12;
|
||||
inertia.I3 = dim2 * std::pow(dim1, 3) / 12;
|
||||
inertia.J = inertia.I2 + inertia.I3;
|
||||
}
|
||||
static void computeMomentsOfInertia(const RectangularBeamDimensions &dimensions,
|
||||
MomentsOfInertia &inertia);
|
||||
double getWidth() const { return dim1; }
|
||||
double getHeight() const { return dim2; }
|
||||
double getDrawingRadius() const override;
|
||||
};
|
||||
|
||||
inline double RectangularBeamDimensions::getDrawingRadius() const
|
||||
{
|
||||
return getWidth() / std::sqrt(2);
|
||||
}
|
||||
|
||||
struct CylindricalBeamDimensions : public BeamDimensions
|
||||
{
|
||||
inline static std::string name{"Cylindrical"};
|
||||
// https://www.engineeringtoolbox.com/area-moment-inertia-d_1328.html
|
||||
CylindricalBeamDimensions(const double &outsideDiameter, const double &insideDiameter)
|
||||
{
|
||||
assert(outsideDiameter > 0 && insideDiameter > 0 && outsideDiameter > insideDiameter);
|
||||
dim1 = insideDiameter;
|
||||
dim2 = outsideDiameter;
|
||||
updateProperties();
|
||||
}
|
||||
CylindricalBeamDimensions()
|
||||
{
|
||||
dim1 = 0.026;
|
||||
dim2 = 0.03;
|
||||
updateProperties();
|
||||
}
|
||||
void updateProperties()
|
||||
{
|
||||
A = M_PI * (std::pow(getOutterDiameter(), 2) - std::pow(getInnerDiameter(), 2)) / 4;
|
||||
inertia.I2 = M_PI * (std::pow(getOutterDiameter(), 4) - std::pow(getInnerDiameter(), 4))
|
||||
/ 64;
|
||||
inertia.I3 = inertia.I2;
|
||||
inertia.J = inertia.I2 + inertia.I3;
|
||||
}
|
||||
double getInnerDiameter() const { return dim1; }
|
||||
double getOutterDiameter() const { return dim2; }
|
||||
double getDrawingRadius() const override;
|
||||
};
|
||||
|
||||
inline double CylindricalBeamDimensions::getDrawingRadius() const
|
||||
{
|
||||
return getOutterDiameter();
|
||||
}
|
||||
|
||||
struct ElementMaterial
|
||||
{
|
||||
double poissonsRatio;
|
||||
double youngsModulus;
|
||||
double G;
|
||||
ElementMaterial(const double &poissonsRatio, const double &youngsModulus)
|
||||
: poissonsRatio(poissonsRatio), youngsModulus(youngsModulus)
|
||||
{
|
||||
assert(poissonsRatio <= 0.5 && poissonsRatio >= -1);
|
||||
updateShearModulus();
|
||||
}
|
||||
ElementMaterial() : poissonsRatio(0.3), youngsModulus(1e9) { updateShearModulus(); }
|
||||
std::string toString() const
|
||||
{
|
||||
return std::string("Material:") + std::string("\nPoisson's ratio=")
|
||||
+ std::to_string(poissonsRatio) + std::string("\nYoung's Modulus(GPa)=")
|
||||
+ std::to_string(youngsModulus / 1e9);
|
||||
}
|
||||
void updateShearModulus() { G = youngsModulus / (2 * (1 + poissonsRatio)); }
|
||||
};
|
||||
|
||||
#endif // BEAM_HPP
|
File diff suppressed because it is too large
Load Diff
|
@ -1,304 +0,0 @@
|
|||
#ifndef BEAMFORMFINDER_HPP
|
||||
#define BEAMFORMFINDER_HPP
|
||||
|
||||
//#ifdef USE_MATPLOT
|
||||
//#include "matplot.h"
|
||||
#include <matplot/matplot.h>
|
||||
//#endif
|
||||
#include "simulationmesh.hpp"
|
||||
#include "simulationmodel.hpp"
|
||||
#include <Eigen/Dense>
|
||||
#include <filesystem>
|
||||
#include <unordered_set>
|
||||
|
||||
#ifdef USE_ENSMALLEN
|
||||
#include <armadillo>
|
||||
#include <ensmallen.hpp>
|
||||
#endif
|
||||
|
||||
class SimulationJob;
|
||||
|
||||
enum DoF { Ux = 0, Uy, Uz, Nx, Ny, Nr, NumDoF };
|
||||
using DoFType = int;
|
||||
using EdgeType = VCGEdgeMesh::EdgeType;
|
||||
using VertexType = VCGEdgeMesh::VertexType;
|
||||
|
||||
struct DifferentiateWithRespectTo {
|
||||
const VertexType &v;
|
||||
const DoFType &dofi;
|
||||
};
|
||||
|
||||
class DRMSimulationModel : public SimulationModel
|
||||
{
|
||||
public:
|
||||
struct Settings
|
||||
{
|
||||
bool useTranslationalKineticEnergyForKineticDamping{true};
|
||||
bool useTotalRotationalKineticEnergyForKineticDamping{false};
|
||||
bool shouldDraw{false};
|
||||
bool beVerbose{false};
|
||||
bool shouldCreatePlots{false};
|
||||
// int drawingStep{0};
|
||||
// double residualForcesMovingAverageDerivativeNormThreshold{1e-8};
|
||||
// double residualForcesMovingAverageNormThreshold{1e-8};
|
||||
double Dtini{0.1};
|
||||
double xi{0.9969};
|
||||
std::optional<double> translationalKineticEnergyThreshold;
|
||||
int gradualForcedDisplacementSteps{50};
|
||||
// int desiredGradualExternalLoadsSteps{1};
|
||||
double gamma{0.8};
|
||||
std::optional<double> totalResidualForcesNormThreshold;
|
||||
double totalExternalForcesNormPercentageTermination{1e-5};
|
||||
std::optional<int> maxDRMIterations;
|
||||
std::optional<int> debugModeStep;
|
||||
std::optional<double> totalTranslationalKineticEnergyThreshold;
|
||||
std::optional<double> averageResidualForcesCriterionThreshold;
|
||||
std::optional<double> linearGuessForceScaleFactor;
|
||||
// std::optional<int> intermediateResultsSaveStep;
|
||||
std::optional<bool> saveIntermediateBestStates;
|
||||
std::optional<double> viscousDampingFactor;
|
||||
Settings() {}
|
||||
void save(const std::filesystem::path &jsonFilePath) const;
|
||||
bool load(const std::filesystem::path &filePath);
|
||||
struct JsonLabels
|
||||
{
|
||||
const std::string shouldDraw{"shouldDraw"};
|
||||
const std::string beVerbose{"beVerbose"};
|
||||
const std::string shouldCreatePlots{"shouldCreatePlots"};
|
||||
const std::string Dtini{"DtIni"};
|
||||
const std::string xi{"xi"};
|
||||
const std::string gamma{"gamma"};
|
||||
const std::string totalResidualForcesNormThreshold;
|
||||
const std::string maxDRMIterations{"maxIterations"};
|
||||
const std::string debugModeStep{"debugModeStep"};
|
||||
const std::string totalTranslationalKineticEnergyThreshold{
|
||||
"totalTranslationaKineticEnergyThreshold"};
|
||||
const std::string averageResidualForcesCriterionThreshold{
|
||||
"averageResidualForcesThreshold"};
|
||||
const std::string linearGuessForceScaleFactor{"linearGuessForceScaleFactor"};
|
||||
const std::string viscousDampingFactor{"viscousDampingFactor"};
|
||||
};
|
||||
static JsonLabels jsonLabels;
|
||||
};
|
||||
inline const static std::string label{"DRM"};
|
||||
|
||||
private:
|
||||
Settings mSettings;
|
||||
double Dt{mSettings.Dtini};
|
||||
bool checkedForMaximumMoment{false};
|
||||
bool shouldTemporarilyDampForces{false};
|
||||
bool shouldTemporarilyAmplifyForces{true};
|
||||
double externalMomentsNorm{0};
|
||||
size_t mCurrentSimulationStep{0};
|
||||
matplot::line_handle plotHandle;
|
||||
std::vector<double> plotYValues;
|
||||
size_t numOfDampings{0};
|
||||
int externalLoadStep{1};
|
||||
std::vector<bool> isVertexConstrained;
|
||||
std::vector<bool> isRigidSupport;
|
||||
double minTotalResidualForcesNorm{std::numeric_limits<double>::max()};
|
||||
|
||||
const std::string meshPolyscopeLabel{"Simulation mesh"};
|
||||
std::unique_ptr<SimulationMesh> pMesh;
|
||||
std::unordered_map<VertexIndex, std::unordered_set<DoFType>> constrainedVertices;
|
||||
SimulationHistory history;
|
||||
// Eigen::Tensor<double, 4> theta3Derivatives;
|
||||
// std::unordered_map<MyKeyType, double, key_hash> theta3Derivatives;
|
||||
bool shouldApplyInitialDistortion{false};
|
||||
//#ifdef USE_ENSMALLEN
|
||||
// std::shared_ptr<SimulationJob> pJob;
|
||||
//#endif
|
||||
void reset(const std::shared_ptr<SimulationJob> &pJob, const Settings &settings);
|
||||
void updateNodalInternalForces(
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices);
|
||||
void updateNodalExternalForces(
|
||||
const std::unordered_map<VertexIndex, Vector6d> &nodalForces,
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices);
|
||||
void updateResidualForces();
|
||||
void updateRotationalDisplacements();
|
||||
void updateElementalLengths();
|
||||
|
||||
void updateNodalMasses();
|
||||
|
||||
void updateNodalAccelerations();
|
||||
|
||||
void updateNodalVelocities();
|
||||
|
||||
void updateNodalDisplacements();
|
||||
|
||||
void applyForcedDisplacements(
|
||||
const std::unordered_map<VertexIndex, Eigen::Vector3d> &nodalForcedDisplacements);
|
||||
|
||||
Vector6d computeElementTorsionalForce(const Element &element,
|
||||
const Vector6d &displacementDifference,
|
||||
const std::unordered_set<DoFType> &constrainedDof);
|
||||
|
||||
// BeamFormFinder::Vector6d computeElementFirstBendingForce(
|
||||
// const Element &element, const Vector6d &displacementDifference,
|
||||
// const std::unordered_set<gsl::index> &constrainedDof);
|
||||
|
||||
// BeamFormFinder::Vector6d computeElementSecondBendingForce(
|
||||
// const Element &element, const Vector6d &displacementDifference,
|
||||
// const std::unordered_set<gsl::index> &constrainedDof);
|
||||
|
||||
void updateKineticEnergy();
|
||||
|
||||
void resetVelocities();
|
||||
|
||||
SimulationResults computeResults(const std::shared_ptr<SimulationJob> &pJob);
|
||||
|
||||
void updateNodePosition(
|
||||
VertexType &v,
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices);
|
||||
|
||||
void applyDisplacements(
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices);
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
void draw(const std::shared_ptr<SimulationJob> &pJob, const std::string &screenshotsFolder = {});
|
||||
#endif
|
||||
void
|
||||
updateNodalInternalForce(Vector6d &nodalInternalForce,
|
||||
const Vector6d &elementInternalForce,
|
||||
const std::unordered_set<DoFType> &nodalFixedDof);
|
||||
|
||||
Vector6d computeElementInternalForce(
|
||||
const Element &elem, const Node &n0, const Node &n1,
|
||||
const std::unordered_set<DoFType> &n0ConstrainedDof,
|
||||
const std::unordered_set<DoFType> &n1ConstrainedDof);
|
||||
|
||||
Vector6d computeElementAxialForce(const ::EdgeType &e) const;
|
||||
VectorType computeDisplacementDifferenceDerivative(
|
||||
const EdgeType &e, const DifferentiateWithRespectTo &dui) const;
|
||||
double
|
||||
computeDerivativeElementLength(const EdgeType &e,
|
||||
const DifferentiateWithRespectTo &dui) const;
|
||||
|
||||
VectorType computeDerivativeT1(const EdgeType &e,
|
||||
const DifferentiateWithRespectTo &dui) const;
|
||||
|
||||
VectorType
|
||||
computeDerivativeOfNormal(const VertexType &v,
|
||||
const DifferentiateWithRespectTo &dui) const;
|
||||
|
||||
VectorType computeDerivativeT3(const EdgeType &e,
|
||||
const DifferentiateWithRespectTo &dui) const;
|
||||
|
||||
VectorType computeDerivativeT2(const EdgeType &e,
|
||||
const DifferentiateWithRespectTo &dui) const;
|
||||
|
||||
double computeDerivativeTheta2(const EdgeType &e, const VertexIndex &evi,
|
||||
const VertexIndex &dwrt_evi,
|
||||
const DoFType &dwrt_dofi) const;
|
||||
|
||||
void updateElementalFrames();
|
||||
|
||||
VectorType computeDerivativeOfR(const EdgeType &e,
|
||||
const DifferentiateWithRespectTo &dui) const;
|
||||
|
||||
|
||||
static double computeDerivativeOfNorm(const VectorType &x,
|
||||
const VectorType &derivativeOfX);
|
||||
static VectorType computeDerivativeOfCrossProduct(
|
||||
const VectorType &a, const VectorType &derivativeOfA, const VectorType &b,
|
||||
const VectorType &derivativeOfB);
|
||||
|
||||
double computeTheta3(const EdgeType &e, const VertexType &v);
|
||||
double computeDerivativeTheta3(const EdgeType &e, const VertexType &v,
|
||||
const DifferentiateWithRespectTo &dui) const;
|
||||
double computeTotalPotentialEnergy();
|
||||
void computeRigidSupports();
|
||||
void updateNormalDerivatives();
|
||||
void updateT1Derivatives();
|
||||
void updateT2Derivatives();
|
||||
void updateT3Derivatives();
|
||||
void updateRDerivatives();
|
||||
|
||||
double computeDerivativeTheta1(const EdgeType &e, const VertexIndex &evi,
|
||||
const VertexIndex &dwrt_evi,
|
||||
const DoFType &dwrt_dofi) const;
|
||||
|
||||
// void updatePositionsOnTheFly(
|
||||
// const std::unordered_map<VertexIndex,
|
||||
// std::unordered_set<gsl::index>>
|
||||
// &fixedVertices);
|
||||
|
||||
void updateResidualForcesOnTheFly(
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
|
||||
&fixedVertices);
|
||||
|
||||
void updatePositionsOnTheFly(
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
|
||||
&fixedVertices);
|
||||
|
||||
void updateNodeNormal(
|
||||
VertexType &v,
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>>
|
||||
&fixedVertices);
|
||||
|
||||
void applyForcedNormals(
|
||||
const std::unordered_map<VertexIndex, VectorType> nodalForcedRotations);
|
||||
|
||||
void printCurrentState() const;
|
||||
|
||||
void printDebugInfo() const;
|
||||
|
||||
double computeTotalInternalPotentialEnergy();
|
||||
|
||||
void applySolutionGuess(const SimulationResults &solutionGuess,
|
||||
const std::shared_ptr<SimulationJob> &pJob);
|
||||
|
||||
void updateNodeNr(VertexType &v);
|
||||
|
||||
void applyKineticDamping(const std::shared_ptr<SimulationJob> &pJob);
|
||||
|
||||
virtual SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &pJob) override;
|
||||
void setStructure(const std::shared_ptr<SimulationMesh> &pMesh) override;
|
||||
|
||||
void reset(const std::shared_ptr<SimulationJob> &pJob);
|
||||
|
||||
std::vector<std::array<Vector6d, 4>> computeInternalForces(
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices);
|
||||
|
||||
void updateDerivatives();
|
||||
|
||||
public:
|
||||
DRMSimulationModel();
|
||||
SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
|
||||
const Settings &settings,
|
||||
const SimulationResults &solutionGuess = SimulationResults());
|
||||
//#ifdef USE_ENSMALLEN
|
||||
// std::shared_ptr<SimulationJob> pJob;
|
||||
// double EvaluateWithGradient(const arma::mat &x, arma::mat &g);
|
||||
// void setJob(const std::shared_ptr<SimulationJob> &pJob);
|
||||
// SimulationMesh *getDeformedMesh(const arma::mat &x, const std::shared_ptr<SimulationJob> &pJob);
|
||||
// double Evaluate(const arma::mat &x);
|
||||
//#endif
|
||||
|
||||
static void runUnitTests();
|
||||
};
|
||||
|
||||
inline DRMSimulationModel::Settings::JsonLabels DRMSimulationModel::Settings::jsonLabels;
|
||||
|
||||
template <typename PointType> PointType Cross(PointType p1, PointType p2) {
|
||||
return p1 ^ p2;
|
||||
}
|
||||
|
||||
inline size_t currentStep{0};
|
||||
inline bool TriggerBreakpoint(const VertexIndex &vi, const EdgeIndex &ei,
|
||||
const DoFType &dofi) {
|
||||
const size_t numberOfVertices = 10;
|
||||
const VertexIndex middleNodeIndex = numberOfVertices / 2;
|
||||
// return vi == middleNodeIndex && dofi == 1;
|
||||
return dofi == 1 && ((vi == 1 && ei == 0) || (vi == 9 && ei == 9));
|
||||
}
|
||||
|
||||
inline bool TriggerBreakpoint(const VertexIndex &vi, const EdgeIndex &ei) {
|
||||
const size_t numberOfVertices = 10;
|
||||
const VertexIndex middleNodeIndex = numberOfVertices / 2;
|
||||
return (vi == middleNodeIndex);
|
||||
// return (vi == 0 || vi == numberOfVertices - 1) && currentStep == 1;
|
||||
return (vi == 1 && ei == 0) || (vi == 9 && ei == 9);
|
||||
}
|
||||
|
||||
#endif // BEAMFORMFINDER_HPP
|
608
edgemesh.cpp
608
edgemesh.cpp
|
@ -1,608 +0,0 @@
|
|||
#include "edgemesh.hpp"
|
||||
#include "vcg/simplex/face/topology.h"
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
//#include <wrap/nanoply/include/nanoplyWrapper.hpp>
|
||||
#include <wrap/io_trimesh/export.h>
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
|
||||
Eigen::MatrixX2i VCGEdgeMesh::getEigenEdges() const { return eigenEdges; }
|
||||
|
||||
std::vector<vcg::Point2i> VCGEdgeMesh::computeEdges()
|
||||
{
|
||||
computeEdges(eigenEdges);
|
||||
std::vector<vcg::Point2i> edges(eigenEdges.rows());
|
||||
for (int ei = 0; ei < eigenEdges.rows(); ei++) {
|
||||
edges[ei] = vcg::Point2i(eigenEdges(ei, 0), eigenEdges(ei, 1));
|
||||
}
|
||||
return edges;
|
||||
}
|
||||
|
||||
Eigen::MatrixX3d VCGEdgeMesh::getEigenVertices() const
|
||||
{
|
||||
// getVertices(eigenVertices);
|
||||
return eigenVertices;
|
||||
}
|
||||
|
||||
Eigen::MatrixX3d VCGEdgeMesh::getEigenEdgeNormals() const {
|
||||
return eigenEdgeNormals;
|
||||
}
|
||||
|
||||
bool VCGEdgeMesh::save(const std::filesystem::path &meshFilePath)
|
||||
{
|
||||
std::string filename = meshFilePath;
|
||||
if (filename.empty()) {
|
||||
filename = std::filesystem::current_path().append(getLabel() + ".ply").string();
|
||||
} else if (std::filesystem::is_directory(std::filesystem::path(meshFilePath))) {
|
||||
filename = std::filesystem::path(meshFilePath).append(getLabel() + ".ply").string();
|
||||
}
|
||||
assert(std::filesystem::path(filename).extension().string() == ".ply");
|
||||
unsigned int mask = 0;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTCOORD;
|
||||
mask |= vcg::tri::io::Mask::IOM_EDGEINDEX;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTCOLOR;
|
||||
// if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::SaveModel(filename.c_str(), *this, mask, false) != 0) {
|
||||
if (std::filesystem::is_directory(meshFilePath.parent_path())) {
|
||||
std::filesystem::create_directories(meshFilePath.parent_path());
|
||||
}
|
||||
if (vcg::tri::io::Exporter<VCGEdgeMesh>::Save(*this, filename.c_str(), mask) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::GeneratedRegularSquaredPattern(
|
||||
const double angleDeg, std::vector<std::vector<vcg::Point2d>> &pattern,
|
||||
const size_t &desiredNumberOfSamples) {
|
||||
static const size_t piSamples = 10;
|
||||
|
||||
// generate a pattern in a 1x1 quad
|
||||
const vcg::Point2d offset(0, 0);
|
||||
|
||||
const size_t samplesNo = desiredNumberOfSamples;
|
||||
// std::max(desiredNumberOfSamples, size_t(piSamples * (angleDeg /
|
||||
// 180)));
|
||||
const double angle = vcg::math::ToRad(angleDeg);
|
||||
|
||||
pattern.clear();
|
||||
|
||||
// first arm
|
||||
std::vector<vcg::Point2d> arm;
|
||||
{
|
||||
for (int k = 0; k <= samplesNo; k++) {
|
||||
const double t = double(k) / samplesNo;
|
||||
const double a = (1 - t) * angle;
|
||||
// const double r = vcg::math::Sin(t*M_PI_2) /*(1-((1-t)*(1-t)))*/ *
|
||||
// 0.5;
|
||||
const double r = t * 0.5; // linear
|
||||
|
||||
vcg::Point2d p(vcg::math::Cos(a), vcg::math::Sin(a));
|
||||
|
||||
arm.push_back((p * r));
|
||||
}
|
||||
pattern.push_back(arm);
|
||||
}
|
||||
|
||||
// other arms
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (vcg::Point2d &p : arm) {
|
||||
p = vcg::Point2d(-p.Y(), p.X());
|
||||
}
|
||||
pattern.push_back(arm);
|
||||
}
|
||||
|
||||
assert(pattern.size() == 4);
|
||||
|
||||
// offset all
|
||||
for (auto &arm : pattern) {
|
||||
for (vcg::Point2d &p : arm) {
|
||||
p += offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::createSpiral(const float °reesOfArm,
|
||||
const size_t &numberOfSamples) {
|
||||
std::vector<std::vector<vcg::Point2d>> spiralPoints;
|
||||
GeneratedRegularSquaredPattern(degreesOfArm, spiralPoints, numberOfSamples);
|
||||
|
||||
for (size_t armIndex = 0; armIndex < spiralPoints.size(); armIndex++) {
|
||||
for (size_t pointIndex = 0; pointIndex < spiralPoints[armIndex].size() - 1;
|
||||
pointIndex++) {
|
||||
const vcg::Point2d p0 = spiralPoints[armIndex][pointIndex];
|
||||
const vcg::Point2d p1 = spiralPoints[armIndex][pointIndex + 1];
|
||||
CoordType n(0, 0, 1);
|
||||
auto ei = vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(
|
||||
*this, VCGEdgeMesh::CoordType(p0.X(), p0.Y(), 0),
|
||||
VCGEdgeMesh::CoordType(p1.X(), p1.Y(), 0));
|
||||
ei->cV(0)->N() = n;
|
||||
ei->cV(1)->N() = n;
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultAttributes();
|
||||
}
|
||||
|
||||
bool VCGEdgeMesh::createSpanGrid(const size_t squareGridDimension) {
|
||||
return createSpanGrid(squareGridDimension, squareGridDimension);
|
||||
}
|
||||
|
||||
bool VCGEdgeMesh::createSpanGrid(const size_t desiredWidth,
|
||||
const size_t desiredHeight) {
|
||||
std::cout << "Grid of dimensions:" << desiredWidth << "," << desiredHeight
|
||||
<< std::endl;
|
||||
const VCGEdgeMesh::CoordType n(0, 0, 1);
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
// for (size_t vi = 0; vi < numberOfVertices; vi++) {
|
||||
while (y <= desiredHeight) {
|
||||
// std::cout << x << " " << y << std::endl;
|
||||
auto p = VCGEdgeMesh::CoordType(x, y, 0);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(*this, p, n);
|
||||
x++;
|
||||
if (x > desiredWidth) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t vi = 0; vi < VN(); vi++) {
|
||||
int x = vi % (desiredWidth + 1);
|
||||
int y = vi / (desiredWidth + 1);
|
||||
const bool isCornerNode = (y == 0 && x == 0) ||
|
||||
(y == 0 && x == desiredWidth) ||
|
||||
(y == desiredHeight && x == 0) ||
|
||||
(y == desiredHeight && x == desiredWidth);
|
||||
if (isCornerNode) {
|
||||
continue;
|
||||
}
|
||||
if (y == 0) { // row 0.Connect with node above
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi,
|
||||
vi + desiredWidth + 1);
|
||||
continue;
|
||||
} else if (x == 0) { // col 0.Connect with node to the right
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi + 1);
|
||||
continue;
|
||||
} else if (y == desiredHeight) { // row 0.Connect with node below
|
||||
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi,
|
||||
// vi - (desiredWidth +
|
||||
// 1));
|
||||
continue;
|
||||
} else if (x == desiredWidth) { // row 0.Connect with node to the left
|
||||
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi + desiredWidth + 1);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi + 1);
|
||||
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi,
|
||||
// vi - (desiredWidth + 1));
|
||||
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi - 1);
|
||||
}
|
||||
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(*this, vert[0]);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(*this, vert[desiredWidth]);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(
|
||||
*this, vert[desiredHeight * (desiredWidth + 1)]);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(
|
||||
*this, vert[(desiredHeight + 1) * (desiredWidth + 1) - 1]);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::CompactVertexVector(*this);
|
||||
computeEdges(eigenEdges);
|
||||
computeVertices(eigenVertices);
|
||||
// vcg::tri::Allocator<VCGEdgeMesh>::CompactEdgeVector(*this);
|
||||
|
||||
// const size_t numberOfEdges =
|
||||
// desiredHeight * (desiredWidth - 1) + desiredWidth * (desiredHeight -
|
||||
// 1);
|
||||
// handleBeamDimensions._handle->data.resize(
|
||||
// numberOfEdges, CylindricalElementDimensions(0.03, 0.026));
|
||||
// handleBeamMaterial._handle->data.resize(numberOfEdges,
|
||||
// ElementMaterial(0.3, 200));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VCGEdgeMesh::load(const std::filesystem::path &meshFilePath)
|
||||
{
|
||||
std::string usedPath = meshFilePath;
|
||||
if (std::filesystem::path(meshFilePath).is_relative()) {
|
||||
usedPath = std::filesystem::absolute(meshFilePath).string();
|
||||
}
|
||||
assert(std::filesystem::exists(usedPath));
|
||||
Clear();
|
||||
// if (!loadUsingNanoply(usedPath)) {
|
||||
// std::cerr << "Error: Unable to open " + usedPath << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
if (!loadUsingDefaultLoader(usedPath)) {
|
||||
std::cerr << "Error: Unable to open " + usedPath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
computeEdges(eigenEdges);
|
||||
computeVertices(eigenVertices);
|
||||
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
|
||||
label = std::filesystem::path(meshFilePath).stem().string();
|
||||
|
||||
const bool printDebugInfo = false;
|
||||
if (printDebugInfo) {
|
||||
std::cout << meshFilePath << " was loaded successfuly." << std::endl;
|
||||
std::cout << "Mesh has " << EN() << " edges." << std::endl;
|
||||
}
|
||||
|
||||
label = std::filesystem::path(meshFilePath).stem().string();
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) {
|
||||
|
||||
// this->Clear();
|
||||
// // assert(plyFileHasAllRequiredFields(plyFilename));
|
||||
// // Load the ply file
|
||||
// unsigned int mask = 0;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOLOR;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
|
||||
// if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::LoadModel(plyFilename.c_str(),
|
||||
// *this, mask) != 0) {
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
//}
|
||||
|
||||
bool VCGEdgeMesh::loadUsingDefaultLoader(const std::string &plyFilePath)
|
||||
{
|
||||
Clear();
|
||||
// assert(plyFileHasAllRequiredFields(plyFilename));
|
||||
// Load the ply file
|
||||
int mask = 0;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTCOORD;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTCOLOR;
|
||||
mask |= vcg::tri::io::Mask::IOM_EDGEINDEX;
|
||||
// if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::LoadModel(plyFilename.c_str(),
|
||||
// *this, mask) != 0) {
|
||||
const int loadErrorCode = vcg::tri::io::Importer<VCGEdgeMesh>::Open(*this,
|
||||
plyFilePath.c_str(),
|
||||
mask);
|
||||
if (loadErrorCode != 0) {
|
||||
std::cerr << vcg::tri::io::Importer<VCGEdgeMesh>::ErrorMsg(loadErrorCode) << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// bool VCGEdgeMesh::plyFileHasAllRequiredFields(const std::string
|
||||
// &plyFilename)
|
||||
// {
|
||||
// const nanoply::Info info(plyFilename);
|
||||
// const std::vector<nanoply::PlyElement>::const_iterator edgeElemIt =
|
||||
// std::find_if(info.elemVec.begin(), info.elemVec.end(),
|
||||
// [&](const nanoply::PlyElement &plyElem) {
|
||||
// return plyElem.plyElem == nanoply::NNP_EDGE_ELEM;
|
||||
// });
|
||||
// if (edgeElemIt == info.elemVec.end()) {
|
||||
// std::cerr << "Ply file is missing edge elements." << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// const std::vector<nanoply::PlyProperty> &edgePropertyVector =
|
||||
// edgeElemIt->propVec;
|
||||
// return hasPlyEdgeProperty(plyFilename, edgePropertyVector,
|
||||
// plyPropertyBeamDimensionsID) &&
|
||||
// hasPlyEdgeProperty(plyFilename, edgePropertyVector,
|
||||
// plyPropertyBeamMaterialID);
|
||||
//}
|
||||
|
||||
Eigen::MatrixX3d VCGEdgeMesh::getNormals() const {
|
||||
Eigen::MatrixX3d vertexNormals;
|
||||
vertexNormals.resize(VN(), 3);
|
||||
|
||||
for (int vertexIndex = 0; vertexIndex < VN(); vertexIndex++) {
|
||||
VCGEdgeMesh::CoordType vertexNormal =
|
||||
vert[static_cast<size_t>(vertexIndex)].cN();
|
||||
vertexNormals.row(vertexIndex) =
|
||||
vertexNormal.ToEigenVector<Eigen::Vector3d>();
|
||||
}
|
||||
|
||||
return vertexNormals;
|
||||
}
|
||||
void VCGEdgeMesh::computeEdges(Eigen::MatrixX3d &edgeStartingPoints,
|
||||
Eigen::MatrixX3d &edgeEndingPoints) const
|
||||
{
|
||||
edgeStartingPoints.resize(EN(), 3);
|
||||
edgeEndingPoints.resize(EN(), 3);
|
||||
for (int edgeIndex = 0; edgeIndex < EN(); edgeIndex++) {
|
||||
const VCGEdgeMesh::EdgeType &edge = this->edge[edgeIndex];
|
||||
edgeStartingPoints.row(edgeIndex) = edge.cP(0).ToEigenVector<Eigen::Vector3d>();
|
||||
edgeEndingPoints.row(edgeIndex) = edge.cP(1).ToEigenVector<Eigen::Vector3d>();
|
||||
}
|
||||
}
|
||||
|
||||
VCGEdgeMesh::VCGEdgeMesh() {}
|
||||
|
||||
void VCGEdgeMesh::updateEigenEdgeAndVertices() {
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
computeEdges(eigenEdges);
|
||||
computeVertices(eigenVertices);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VCGEdgeMesh::copy(const VCGEdgeMesh &mesh)
|
||||
{
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::MeshCopyConst(*this, mesh);
|
||||
label = mesh.getLabel();
|
||||
eigenEdges = mesh.getEigenEdges();
|
||||
// assert(eigenEdges.rows() != 0);
|
||||
// if (eigenEdges.rows() == 0) {
|
||||
// getEdges(eigenEdges);
|
||||
// }
|
||||
eigenVertices = mesh.getEigenVertices();
|
||||
// assert(eigenVertices.rows() != 0);
|
||||
// if (eigenVertices.rows() == 0) {
|
||||
// getVertices(eigenVertices);
|
||||
// }
|
||||
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::set(const std::vector<double> &vertexPositions, const std::vector<int> &edges)
|
||||
{
|
||||
Clear();
|
||||
for (int ei = 0; ei < edges.size(); ei += 2) {
|
||||
const int vi0 = edges[ei];
|
||||
const int vi1 = edges[ei + 1];
|
||||
const int vi0_offset = 3 * vi0;
|
||||
const int vi1_offset = 3 * vi1;
|
||||
const CoordType p0(vertexPositions[vi0_offset],
|
||||
vertexPositions[vi0_offset + 1],
|
||||
vertexPositions[vi0_offset + 2]);
|
||||
const CoordType p1(vertexPositions[vi1_offset],
|
||||
vertexPositions[vi1_offset + 1],
|
||||
vertexPositions[vi1_offset + 2]);
|
||||
auto eIt = vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, p0, p1);
|
||||
CoordType n(0, 0, 1);
|
||||
eIt->cV(0)->N() = n;
|
||||
eIt->cV(1)->N() = n;
|
||||
}
|
||||
// removeDuplicateVertices();
|
||||
|
||||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::removeDuplicateVertices()
|
||||
{
|
||||
vcg::tri::Clean<VCGEdgeMesh>::MergeCloseVertex(*this, 0.000061524);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::CompactVertexVector(*this);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::CompactEdgeVector(*this);
|
||||
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::removeDuplicateVertices(
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> &pu_vertices,
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<EdgePointer> &pu_edges)
|
||||
{
|
||||
vcg::tri::Clean<VCGEdgeMesh>::MergeCloseVertex(*this, 0.000061524);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::CompactVertexVector(*this, pu_vertices);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::CompactEdgeVector(*this, pu_edges);
|
||||
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
|
||||
}
|
||||
|
||||
std::string VCGEdgeMesh::ToSvgText(const VCGEdgeMesh &edgeMesh)
|
||||
{
|
||||
// Measures in mm (?)
|
||||
constexpr double ImgPadding = 5;
|
||||
//constexpr double PatternSize = 200 * 19.230769231;
|
||||
//constexpr double PatternSize = 200 * 17.913461538;
|
||||
constexpr double PatternSize = 1000;
|
||||
constexpr double ImgSize = 2 * ImgPadding + PatternSize;
|
||||
|
||||
constexpr double StrokeWidth = 5;
|
||||
VCGEdgeMesh edgeMeshCopy;
|
||||
edgeMeshCopy.copy(edgeMesh);
|
||||
|
||||
vcg::tri::UpdateBounding<VCGEdgeMesh>::Box(edgeMeshCopy);
|
||||
const double maxDim = edgeMeshCopy.bbox.Dim()[edgeMeshCopy.bbox.MaxDim()];
|
||||
vcg::tri::UpdatePosition<VCGEdgeMesh>::Translate(
|
||||
edgeMeshCopy,
|
||||
VCGEdgeMesh::CoordType(maxDim / 2.0 - edgeMeshCopy.bbox.Center().X(),
|
||||
maxDim / 2.0 - edgeMeshCopy.bbox.Center().Y(),
|
||||
0));
|
||||
vcg::tri::UpdatePosition<VCGEdgeMesh>::Scale(edgeMeshCopy, PatternSize / maxDim);
|
||||
|
||||
// debug
|
||||
// vcg::tri::UpdateBounding<EdgeMesh>::Box(em);
|
||||
// std::cout << "pattern size "
|
||||
// << em.bbox.min.X() << " "
|
||||
// << em.bbox.max.X() << " "
|
||||
// << em.bbox.min.Y() << " "
|
||||
// << em.bbox.max.Y() << " " << std::endl;
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
// svg header
|
||||
ss << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl
|
||||
<< "<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' "
|
||||
"'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>"
|
||||
<< std::endl;
|
||||
|
||||
// size & background
|
||||
ss << "<svg height=\"" << ImgSize << "\" width=\"" << ImgSize
|
||||
<< "\" xmlns=\"http://www.w3.org/2000/svg\" "
|
||||
"xmlns:xlink=\"http://www.w3.org/1999/xlink\">"
|
||||
<< std::endl;
|
||||
ss << "<rect width=\"100%\" height=\"100%\" fill=\"white\"/>" << std::endl;
|
||||
|
||||
for (const auto &e : edgeMeshCopy.edge) {
|
||||
const auto &p0 = e.cP(0);
|
||||
const auto &p1 = e.cP(1);
|
||||
ss << "<line "
|
||||
<< "x1=\"" << ImgPadding + p0.X() << "\" y1=\"" << -ImgPadding - p0.Y() + ImgSize
|
||||
<< "\" "
|
||||
<< "x2=\"" << ImgPadding + p1.X() << "\" y2=\"" << -ImgPadding - p1.Y() + ImgSize
|
||||
<< "\" "
|
||||
<< "style=\"stroke:rgb(67,160,232);stroke-width:" << StrokeWidth
|
||||
<< "\" stroke-linecap=\"round\"/>" << std::endl;
|
||||
}
|
||||
|
||||
ss << "</svg>" << std::endl;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::writeToSvg(const std::filesystem::path &writeToPath) const
|
||||
{
|
||||
// retrieve filepath for saving svg
|
||||
const std::filesystem::path svgPath = [=]() {
|
||||
if (writeToPath.empty()) {
|
||||
return std::filesystem::current_path().append(getLabel()).concat(".svg");
|
||||
}
|
||||
return std::filesystem::absolute(writeToPath);
|
||||
}();
|
||||
// save to svg file
|
||||
std::cout << "saving to " << svgPath << std::endl;
|
||||
|
||||
std::ofstream ofs(svgPath);
|
||||
if (!ofs.is_open()) {
|
||||
std::cout << "unable to save to " << svgPath << std::endl;
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ofs << ToSvgText(*this);
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::deleteDanglingVertices() {
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> pu;
|
||||
deleteDanglingVertices(pu);
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::deleteDanglingVertices(vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<TriMesh::VertexPointer> &pu) {
|
||||
for (VertexType &v : vert) {
|
||||
std::vector<VCGEdgeMesh::EdgePointer> incidentElements;
|
||||
vcg::edge::VEStarVE(&v, incidentElements);
|
||||
if (incidentElements.size() == 0 && !v.IsD()) {
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(*this, v);
|
||||
}
|
||||
}
|
||||
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::CompactVertexVector(*this, pu);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::CompactEdgeVector(*this);
|
||||
|
||||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::computeVertices(Eigen::MatrixX3d &vertices)
|
||||
{
|
||||
vertices = Eigen::MatrixX3d();
|
||||
vertices.resize(VN(), 3);
|
||||
for (int vi = 0; vi < VN(); vi++) {
|
||||
if (vert[vi].IsD()) {
|
||||
continue;
|
||||
}
|
||||
VCGEdgeMesh::CoordType vertexCoordinates =
|
||||
vert[static_cast<size_t>(vi)].cP();
|
||||
vertices.row(vi) = vertexCoordinates.ToEigenVector<Eigen::Vector3d>();
|
||||
}
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::computeEdges(Eigen::MatrixX2i &edges)
|
||||
{
|
||||
edges = Eigen::MatrixX2i();
|
||||
edges.resize(EN(), 2);
|
||||
for (int edgeIndex = 0; edgeIndex < EN(); edgeIndex++) {
|
||||
const VCGEdgeMesh::EdgeType &edge = this->edge[edgeIndex];
|
||||
assert(!edge.IsD());
|
||||
auto vp0 = edge.cV(0);
|
||||
auto vp1 = edge.cV(1);
|
||||
assert(vcg::tri::IsValidPointer(*this, vp0) && vcg::tri::IsValidPointer(*this, vp1));
|
||||
const size_t vi0 = vcg::tri::Index<VCGEdgeMesh>(*this, vp0);
|
||||
const size_t vi1 = vcg::tri::Index<VCGEdgeMesh>(*this, vp1);
|
||||
assert(vi0 != -1 && vi1 != -1);
|
||||
edges.row(edgeIndex) = Eigen::Vector2i(vi0, vi1);
|
||||
}
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::printVertexCoordinates(const size_t &vi) const
|
||||
{
|
||||
std::cout << "vi:" << vi << " " << vert[vi].cP()[0] << " " << vert[vi].cP()[1] << " "
|
||||
<< vert[vi].cP()[2] << std::endl;
|
||||
}
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
void VCGEdgeMesh::markVertices(const std::vector<size_t> &vertsToMark)
|
||||
{
|
||||
if (vertsToMark.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::array<double, 3>> nodeColors(VN(), {0, 0, 0});
|
||||
for (const size_t vi : vertsToMark) {
|
||||
nodeColors[vi] = {1, 0, 0};
|
||||
}
|
||||
|
||||
polyscope::getCurveNetwork(getLabel())
|
||||
->addNodeColorQuantity("Marked vertices" + getLabel(), nodeColors)
|
||||
->setEnabled(true);
|
||||
}
|
||||
|
||||
//TODO: make const getEigenVertices is not
|
||||
polyscope::CurveNetwork *VCGEdgeMesh::registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor,
|
||||
const double &desiredRadius,
|
||||
const bool &shouldEnable)
|
||||
{
|
||||
PolyscopeInterface::init();
|
||||
const double drawingRadius = desiredRadius;
|
||||
updateEigenEdgeAndVertices();
|
||||
polyscope::CurveNetwork *polyscopeHandle_edgeMesh
|
||||
= polyscope::registerCurveNetwork(label, getEigenVertices(), getEigenEdges());
|
||||
// std::cout << "EDGES:" << polyscopeHandle_edgeMesh->nEdges() << std::endl;
|
||||
assert(polyscopeHandle_edgeMesh->nEdges() == getEigenEdges().rows()
|
||||
&& polyscopeHandle_edgeMesh->nNodes() == getEigenVertices().rows());
|
||||
|
||||
polyscopeHandle_edgeMesh->setEnabled(shouldEnable);
|
||||
polyscopeHandle_edgeMesh->setRadius(drawingRadius, false);
|
||||
if (desiredColor.has_value()) {
|
||||
const glm::vec3 desiredColor_glm(desiredColor.value()[0],
|
||||
desiredColor.value()[1],
|
||||
desiredColor.value()[2]);
|
||||
polyscopeHandle_edgeMesh->setColor(/*glm::normalize(*/ desiredColor_glm /*)*/);
|
||||
}
|
||||
|
||||
return polyscopeHandle_edgeMesh;
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::unregister() const {
|
||||
if (!polyscope::hasCurveNetwork(label)) {
|
||||
std::cerr << "No curve network registered with a name: " << getLabel()
|
||||
<< std::endl;
|
||||
std::cerr << "Nothing to remove." << std::endl;
|
||||
return;
|
||||
}
|
||||
polyscope::removeCurveNetwork(label);
|
||||
}
|
||||
|
||||
void VCGEdgeMesh::drawInitialFrames(polyscope::CurveNetwork *polyscopeHandle_initialMesh) const
|
||||
{
|
||||
Eigen::MatrixX3d frameInitialX(VN(), 3);
|
||||
Eigen::MatrixX3d frameInitialY(VN(), 3);
|
||||
Eigen::MatrixX3d frameInitialZ(VN(), 3);
|
||||
for (int vi = 0; vi < VN(); vi++) {
|
||||
frameInitialX.row(vi) = Eigen::Vector3d(1, 0, 0);
|
||||
frameInitialY.row(vi) = Eigen::Vector3d(0, 1, 0);
|
||||
frameInitialZ.row(vi) = Eigen::Vector3d(0, 0, 1);
|
||||
}
|
||||
polyscopeHandle_initialMesh->addNodeVectorQuantity("FrameX", frameInitialX)
|
||||
->setVectorColor(glm::vec3(1, 0, 0))
|
||||
->setEnabled(true);
|
||||
polyscopeHandle_initialMesh->addNodeVectorQuantity("FrameY", frameInitialY)
|
||||
->setVectorColor(glm::vec3(0, 1, 0))
|
||||
->setEnabled(true);
|
||||
polyscopeHandle_initialMesh->addNodeVectorQuantity("FrameZ", frameInitialZ)
|
||||
->setVectorColor(glm::vec3(0, 0, 1))
|
||||
->setEnabled(true);
|
||||
}
|
||||
#endif
|
131
edgemesh.hpp
131
edgemesh.hpp
|
@ -1,131 +0,0 @@
|
|||
#ifndef EDGEMESH_HPP
|
||||
#define EDGEMESH_HPP
|
||||
#include "beam.hpp"
|
||||
#include "mesh.hpp"
|
||||
#include "utilities.hpp"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <vcg/complex/complex.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include <polyscope/curve_network.h>
|
||||
#endif
|
||||
|
||||
using EdgeIndex = size_t;
|
||||
|
||||
class VCGEdgeMeshEdgeType;
|
||||
class VCGEdgeMeshVertexType;
|
||||
|
||||
struct VCGEdgeMeshUsedTypes
|
||||
: public vcg::UsedTypes<vcg::Use<VCGEdgeMeshVertexType>::AsVertexType,
|
||||
vcg::Use<VCGEdgeMeshEdgeType>::AsEdgeType> {};
|
||||
|
||||
class VCGEdgeMeshVertexType
|
||||
: public vcg::Vertex<VCGEdgeMeshUsedTypes, vcg::vertex::Coord3d,
|
||||
vcg::vertex::Normal3d, vcg::vertex::BitFlags,
|
||||
vcg::vertex::Color4b, vcg::vertex::VEAdj> {};
|
||||
class VCGEdgeMeshEdgeType
|
||||
: public vcg::Edge<VCGEdgeMeshUsedTypes, vcg::edge::VertexRef,
|
||||
vcg::edge::BitFlags, vcg::edge::EEAdj,
|
||||
vcg::edge::VEAdj> {};
|
||||
|
||||
class VCGEdgeMesh
|
||||
: public vcg::tri::TriMesh<std::vector<VCGEdgeMeshVertexType>, std::vector<VCGEdgeMeshEdgeType>>,
|
||||
public Mesh
|
||||
{
|
||||
protected:
|
||||
Eigen::MatrixX2i eigenEdges;
|
||||
Eigen::MatrixX3d eigenVertices;
|
||||
Eigen::MatrixX3d eigenEdgeNormals;
|
||||
|
||||
void computeEdges(Eigen::MatrixX2i &edges);
|
||||
void computeVertices(Eigen::MatrixX3d &vertices);
|
||||
|
||||
public:
|
||||
VCGEdgeMesh();
|
||||
template<typename MeshElement>
|
||||
size_t getIndex(const MeshElement &meshElement)
|
||||
{
|
||||
return vcg::tri::Index<VCGEdgeMesh>(*this, meshElement);
|
||||
}
|
||||
void updateEigenEdgeAndVertices();
|
||||
/*
|
||||
* The copy function shold be a virtual function of the base interface Mesh class.
|
||||
* https://stackoverflow.com/questions/2354210/can-a-class-member-function-template-be-virtual
|
||||
* use type erasure (?)
|
||||
* */
|
||||
bool copy(const VCGEdgeMesh &mesh);
|
||||
|
||||
void set(const std::vector<double> &vertexPositions, const std::vector<int> &edges);
|
||||
|
||||
void removeDuplicateVertices();
|
||||
virtual void deleteDanglingVertices();
|
||||
virtual void deleteDanglingVertices(
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> &pu);
|
||||
|
||||
void computeEdges(Eigen::MatrixX3d &edgeStartingPoints, Eigen::MatrixX3d &edgeEndingPoints) const;
|
||||
|
||||
Eigen::MatrixX3d getNormals() const;
|
||||
|
||||
bool plyFileHasAllRequiredFields(const std::string &plyFilename);
|
||||
|
||||
// bool loadUsingNanoply(const std::string &plyFilename);
|
||||
|
||||
bool load(const std::filesystem::path &meshFilePath) override;
|
||||
bool save(const std::filesystem::path &meshFilePath = std::filesystem::path()) override;
|
||||
|
||||
bool createSpanGrid(const size_t squareGridDimension);
|
||||
bool createSpanGrid(const size_t desiredWidth, const size_t desiredHeight);
|
||||
void createSpiral(const float °reesOfArm, const size_t &numberOfSamples);
|
||||
|
||||
Eigen::MatrixX2i getEigenEdges() const;
|
||||
std::vector<vcg::Point2i> computeEdges();
|
||||
|
||||
Eigen::MatrixX3d getEigenVertices() const;
|
||||
Eigen::MatrixX3d getEigenEdgeNormals() const;
|
||||
void printVertexCoordinates(const size_t &vi) const;
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
polyscope::CurveNetwork *registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor = std::nullopt,
|
||||
const double &desiredRadius = 0.001,
|
||||
const bool &shouldEnable = true);
|
||||
void unregister() const;
|
||||
void drawInitialFrames(polyscope::CurveNetwork *polyscopeHandle_initialMesh) const;
|
||||
#endif
|
||||
void removeDuplicateVertices(
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> &pu_vertices,
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<EdgePointer> &pu_edges);
|
||||
|
||||
void centerMesh()
|
||||
{
|
||||
CoordType centerOfMass(0, 0, 0);
|
||||
|
||||
for (const auto &v : vert) {
|
||||
centerOfMass = centerOfMass + v.cP();
|
||||
}
|
||||
centerOfMass = centerOfMass / VN();
|
||||
for (auto &v : vert) {
|
||||
v.P() = v.cP() - centerOfMass;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string ToSvgText(const VCGEdgeMesh &edgeMesh);
|
||||
void writeToSvg(const std::filesystem::path &writeToPath = std::filesystem::path()) const;
|
||||
|
||||
void markVertices(const std::vector<size_t> &vertsToMark);
|
||||
|
||||
private:
|
||||
void GeneratedRegularSquaredPattern(const double angleDeg,
|
||||
std::vector<std::vector<vcg::Point2d>> &pattern,
|
||||
const size_t &desiredNumberOfSamples);
|
||||
bool loadUsingDefaultLoader(const std::string &plyFilePath);
|
||||
};
|
||||
|
||||
using VectorType = VCGEdgeMesh::CoordType;
|
||||
using CoordType = VCGEdgeMesh::CoordType;
|
||||
using VertexPointer = VCGEdgeMesh::VertexPointer;
|
||||
using EdgePointer = VCGEdgeMesh::EdgePointer;
|
||||
using ConstVCGEdgeMesh = VCGEdgeMesh;
|
||||
|
||||
#endif // EDGEMESH_HPP
|
|
@ -1,274 +0,0 @@
|
|||
#include "linearsimulationmodel.hpp"
|
||||
//#include "gsl/gsl"
|
||||
|
||||
std::vector<fea::Elem> LinearSimulationModel::getFeaElements(
|
||||
const std::shared_ptr<SimulationMesh> &pMesh)
|
||||
{
|
||||
const int numberOfEdges = pMesh->EN();
|
||||
std::vector<fea::Elem> elements(numberOfEdges);
|
||||
for (int edgeIndex = 0; edgeIndex < numberOfEdges; edgeIndex++) {
|
||||
const SimulationMesh::CoordType &evn0 = pMesh->edge[edgeIndex].cV(0)->cN();
|
||||
const SimulationMesh::CoordType &evn1 = pMesh->edge[edgeIndex].cV(1)->cN();
|
||||
const std::vector<double> nAverageVector{(evn0[0] + evn1[0]) / 2,
|
||||
(evn0[1] + evn1[1]) / 2,
|
||||
(evn0[2] + evn1[2]) / 2};
|
||||
const Element &element = pMesh->elements[edgeIndex];
|
||||
const double E = element.material.youngsModulus;
|
||||
fea::Props feaProperties(E * element.dimensions.A,
|
||||
E * element.dimensions.inertia.I3,
|
||||
E * element.dimensions.inertia.I2,
|
||||
element.material.G * element.dimensions.inertia.J,
|
||||
nAverageVector);
|
||||
const int vi0 = pMesh->getIndex(pMesh->edge[edgeIndex].cV(0));
|
||||
const int vi1 = pMesh->getIndex(pMesh->edge[edgeIndex].cV(1));
|
||||
elements[edgeIndex] = fea::Elem(vi0, vi1, feaProperties);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
std::vector<fea::Node> LinearSimulationModel::getFeaNodes(
|
||||
const std::shared_ptr<SimulationMesh> &pMesh)
|
||||
{
|
||||
const int numberOfNodes = pMesh->VN();
|
||||
std::vector<fea::Node> feaNodes(numberOfNodes);
|
||||
for (int vi = 0; vi < numberOfNodes; vi++) {
|
||||
const CoordType &p = pMesh->vert[vi].cP();
|
||||
feaNodes[vi] = fea::Node(p[0], p[1], p[2]);
|
||||
}
|
||||
|
||||
return feaNodes;
|
||||
}
|
||||
|
||||
std::vector<fea::BC> LinearSimulationModel::getFeaFixedNodes(
|
||||
const std::shared_ptr<SimulationJob> &job)
|
||||
{
|
||||
std::vector<fea::BC> boundaryConditions;
|
||||
// boundaryConditions.reserve(job->constrainedVertices.size() * 6
|
||||
// + job->nodalForcedDisplacements.size() * 3);
|
||||
for (auto fixedVertex : job->constrainedVertices) {
|
||||
const int vertexIndex = fixedVertex.first;
|
||||
for (int dofIndex : fixedVertex.second) {
|
||||
boundaryConditions.emplace_back(
|
||||
fea::BC(vertexIndex, static_cast<fea::DOF>(dofIndex), 0));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto forcedDisplacement : job->nodalForcedDisplacements) {
|
||||
const int vi = forcedDisplacement.first;
|
||||
for (int dofIndex = 0; dofIndex < 3; dofIndex++) {
|
||||
boundaryConditions.emplace_back(
|
||||
fea::BC(vi, static_cast<fea::DOF>(dofIndex), forcedDisplacement.second[dofIndex]));
|
||||
}
|
||||
}
|
||||
|
||||
return boundaryConditions;
|
||||
}
|
||||
|
||||
std::vector<fea::Force> LinearSimulationModel::getFeaNodalForces(
|
||||
const std::shared_ptr<SimulationJob> &job)
|
||||
{
|
||||
std::vector<fea::Force> nodalForces;
|
||||
nodalForces.reserve(job->nodalExternalForces.size() * 6);
|
||||
|
||||
for (auto nodalForce : job->nodalExternalForces) {
|
||||
for (int dofIndex = 0; dofIndex < 6; dofIndex++) {
|
||||
if (nodalForce.second[dofIndex] == 0) {
|
||||
continue;
|
||||
}
|
||||
fea::Force f(nodalForce.first, dofIndex, nodalForce.second[dofIndex]);
|
||||
nodalForces.emplace_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
return nodalForces;
|
||||
}
|
||||
|
||||
SimulationResults LinearSimulationModel::getResults(
|
||||
const fea::Summary &feaSummary, const std::shared_ptr<SimulationJob> &simulationJob)
|
||||
{
|
||||
SimulationResults results;
|
||||
results.converged = feaSummary.converged;
|
||||
if (!results.converged) {
|
||||
return results;
|
||||
}
|
||||
|
||||
results.executionTime = feaSummary.total_time_in_ms * 1000;
|
||||
// displacements
|
||||
results.displacements.resize(feaSummary.num_nodes);
|
||||
results.rotationalDisplacementQuaternion.resize(feaSummary.num_nodes);
|
||||
for (int vi = 0; vi < feaSummary.num_nodes; vi++) {
|
||||
results.displacements[vi] = Vector6d(feaSummary.nodal_displacements[vi]);
|
||||
|
||||
const Vector6d &nodalDisplacement = results.displacements[vi];
|
||||
Eigen::Quaternion<double> q_nx;
|
||||
q_nx = Eigen::AngleAxis<double>(nodalDisplacement[3], Eigen::Vector3d(1, 0, 0));
|
||||
Eigen::Quaternion<double> q_ny;
|
||||
q_ny = Eigen::AngleAxis<double>(nodalDisplacement[4], Eigen::Vector3d(0, 1, 0));
|
||||
Eigen::Quaternion<double> q_nz;
|
||||
q_nz = Eigen::AngleAxis<double>(nodalDisplacement[5], Eigen::Vector3d(0, 0, 1));
|
||||
results.rotationalDisplacementQuaternion[vi] = q_nx * q_ny * q_nz;
|
||||
}
|
||||
results.setLabelPrefix("Linear");
|
||||
|
||||
// // Convert forces
|
||||
// // Convert to vector of eigen matrices of the form force component-> per
|
||||
// // Edge
|
||||
// const int numDof = 6;
|
||||
// const size_t numberOfEdges = feaSummary.element_forces.size();
|
||||
// edgeForces =
|
||||
// std::vector<Eigen::VectorXd>(numDof, Eigen::VectorXd(2 *
|
||||
// numberOfEdges));
|
||||
// for (gsl::index edgeIndex = 0; edgeIndex < numberOfEdges; edgeIndex++) {
|
||||
// for (gsl::index forceComponentIndex = 0; forceComponentIndex < numDof;
|
||||
// forceComponentIndex++) {
|
||||
// (edgeForces[forceComponentIndex])(2 * edgeIndex) =
|
||||
// feaSummary.element_forces[edgeIndex][forceComponentIndex];
|
||||
// (edgeForces[forceComponentIndex])(2 * edgeIndex + 1) =
|
||||
// feaSummary.element_forces[edgeIndex][numDof +
|
||||
// forceComponentIndex];
|
||||
// }
|
||||
// }
|
||||
|
||||
for (int ei = 0; ei < feaSummary.num_elems; ei++) {
|
||||
const std::vector<double> &elementForces = feaSummary.element_forces[ei];
|
||||
const Element &element = simulationJob->pMesh->elements[ei];
|
||||
//Axial
|
||||
const double elementPotentialEnergy_axial_v0 = std::pow(elementForces[0], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.A);
|
||||
const double elementPotentialEnergy_axial_v1 = std::pow(elementForces[6], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.A);
|
||||
const double elementPotentialEnergy_axial = elementPotentialEnergy_axial_v0
|
||||
+ elementPotentialEnergy_axial_v1;
|
||||
//Shear
|
||||
const double elementPotentialEnergy_shearY_v0 = std::pow(elementForces[1], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shearZ_v0 = std::pow(elementForces[2], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shearY_v1 = std::pow(elementForces[7], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shearZ_v1 = std::pow(elementForces[8], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shear = elementPotentialEnergy_shearY_v0
|
||||
+ elementPotentialEnergy_shearZ_v0
|
||||
+ elementPotentialEnergy_shearY_v1
|
||||
+ elementPotentialEnergy_shearZ_v1;
|
||||
//Bending
|
||||
const double elementPotentialEnergy_bendingY_v0 = std::pow(elementForces[4], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I2);
|
||||
const double elementPotentialEnergy_bendingZ_v0 = std::pow(elementForces[5], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I3);
|
||||
const double elementPotentialEnergy_bendingY_v1 = std::pow(elementForces[10], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I2);
|
||||
const double elementPotentialEnergy_bendingZ_v1 = std::pow(elementForces[11], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I3);
|
||||
const double elementPotentialEnergy_bending = elementPotentialEnergy_bendingY_v0
|
||||
+ elementPotentialEnergy_bendingZ_v0
|
||||
+ elementPotentialEnergy_bendingY_v1
|
||||
+ elementPotentialEnergy_bendingZ_v1;
|
||||
//Torsion
|
||||
const double elementPotentialEnergy_torsion_v0 = std::pow(elementForces[3], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.inertia.J
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_torsion_v1 = std::pow(elementForces[9], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.inertia.J
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_torsion = elementPotentialEnergy_torsion_v0
|
||||
+ elementPotentialEnergy_torsion_v1;
|
||||
const double elementInternalPotentialEnergy = elementPotentialEnergy_axial
|
||||
+ elementPotentialEnergy_shear
|
||||
+ elementPotentialEnergy_bending
|
||||
+ elementPotentialEnergy_torsion;
|
||||
results.internalPotentialEnergy += elementInternalPotentialEnergy;
|
||||
}
|
||||
results.pJob = simulationJob;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
SimulationResults LinearSimulationModel::executeSimulation(
|
||||
const std::shared_ptr<SimulationJob> &pSimulationJob)
|
||||
{
|
||||
assert(pSimulationJob->pMesh->VN() != 0);
|
||||
const bool wasInitializedWithDifferentStructure = pSimulationJob->pMesh->EN()
|
||||
!= simulator.structure.elems.size()
|
||||
|| pSimulationJob->pMesh->VN()
|
||||
!= simulator.structure.nodes.size();
|
||||
if (!simulator.wasInitialized() || wasInitializedWithDifferentStructure) {
|
||||
setStructure(pSimulationJob->pMesh);
|
||||
}
|
||||
// printInfo(job);
|
||||
|
||||
// create the default options
|
||||
fea::Options opts;
|
||||
opts.save_elemental_forces = false;
|
||||
opts.save_nodal_displacements = false;
|
||||
opts.save_nodal_forces = false;
|
||||
opts.save_report = false;
|
||||
opts.save_tie_forces = false;
|
||||
// if (!elementalForcesOutputFilepath.empty()) {
|
||||
// opts.save_elemental_forces = true;
|
||||
// opts.elemental_forces_filename = elementalForcesOutputFilepath;
|
||||
// }
|
||||
// if (!nodalDisplacementsOutputFilepath.empty()) {
|
||||
// opts.save_nodal_displacements = true;
|
||||
// opts.nodal_displacements_filename = nodalDisplacementsOutputFilepath;
|
||||
// }
|
||||
|
||||
// have the program output status updates
|
||||
opts.verbose = false;
|
||||
|
||||
// form an empty vector of ties
|
||||
std::vector<fea::Tie> ties;
|
||||
|
||||
// also create an empty list of equations
|
||||
std::vector<fea::Equation> equations;
|
||||
auto fixedVertices = getFeaFixedNodes(pSimulationJob);
|
||||
auto nodalForces = getFeaNodalForces(pSimulationJob);
|
||||
fea::Summary feaResults = simulator.solve(fixedVertices, nodalForces, ties, equations, opts);
|
||||
|
||||
SimulationResults results = getResults(feaResults, pSimulationJob);
|
||||
results.pJob = pSimulationJob;
|
||||
return results;
|
||||
}
|
||||
|
||||
void LinearSimulationModel::setStructure(const std::shared_ptr<SimulationMesh> &pMesh)
|
||||
{
|
||||
fea::BeamStructure structure(getFeaNodes(pMesh), getFeaElements(pMesh));
|
||||
simulator.initialize(structure);
|
||||
}
|
||||
|
||||
void LinearSimulationModel::printInfo(const fea::BeamStructure &job)
|
||||
{
|
||||
std::cout << "Details regarding the fea::Job:" << std::endl;
|
||||
std::cout << "Nodes:" << std::endl;
|
||||
for (fea::Node n : job.nodes) {
|
||||
std::cout << n << std::endl;
|
||||
}
|
||||
std::cout << "Elements:" << std::endl;
|
||||
for (Eigen::Vector2i e : job.elems) {
|
||||
std::cout << e << std::endl;
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef LINEARSIMULATIONMODEL_HPP
|
||||
#define LINEARSIMULATIONMODEL_HPP
|
||||
|
||||
#include "simulationmodel.hpp"
|
||||
#include "threed_beam_fea.h"
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
class LinearSimulationModel : public SimulationModel
|
||||
{
|
||||
public:
|
||||
LinearSimulationModel(){
|
||||
|
||||
}
|
||||
static std::vector<fea::Elem> getFeaElements(const std::shared_ptr<SimulationMesh> &pMesh);
|
||||
|
||||
static std::vector<fea::Node> getFeaNodes(const std::shared_ptr<SimulationMesh> &pMesh);
|
||||
static std::vector<fea::BC> getFeaFixedNodes(const std::shared_ptr<SimulationJob> &job);
|
||||
|
||||
static std::vector<fea::Force> getFeaNodalForces(const std::shared_ptr<SimulationJob> &job);
|
||||
static SimulationResults getResults(const fea::Summary &feaSummary,
|
||||
const std::shared_ptr<SimulationJob> &simulationJob);
|
||||
|
||||
SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &simulationJob);
|
||||
void setStructure(const std::shared_ptr<SimulationMesh> &pMesh);
|
||||
|
||||
private:
|
||||
fea::ThreedBeamFEA simulator;
|
||||
static void printInfo(const fea::BeamStructure &job);
|
||||
};
|
||||
|
||||
#endif // LINEARSIMULATIONMODEL_HPP
|
37
mesh.hpp
37
mesh.hpp
|
@ -1,37 +0,0 @@
|
|||
#ifndef MESH_HPP
|
||||
#define MESH_HPP
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
class Mesh
|
||||
{
|
||||
protected:
|
||||
std::string label{"empty_label"};
|
||||
|
||||
public:
|
||||
virtual ~Mesh() = default;
|
||||
virtual bool load(const std::filesystem::path &meshFilePath) { return false; }
|
||||
virtual bool save(const std::filesystem::path &meshFilePath) { return false; }
|
||||
|
||||
std::string getLabel() const;
|
||||
void setLabel(const std::string &newLabel);
|
||||
void prependToLabel(const std::string &text);
|
||||
void appendToLabel(const std::string &text);
|
||||
};
|
||||
|
||||
inline std::string Mesh::getLabel() const { return label; }
|
||||
|
||||
inline void Mesh::setLabel(const std::string &newLabel) { label = newLabel; }
|
||||
|
||||
inline void Mesh::prependToLabel(const std::string &text)
|
||||
{
|
||||
label = text + label;
|
||||
}
|
||||
|
||||
inline void Mesh::appendToLabel(const std::string &text)
|
||||
{
|
||||
label = label + text;
|
||||
}
|
||||
|
||||
#endif // MESH_HPP
|
File diff suppressed because it is too large
Load Diff
|
@ -1,176 +0,0 @@
|
|||
#ifndef SIMULATIONHISTORYPLOTTER_HPP
|
||||
#define SIMULATIONHISTORYPLOTTER_HPP
|
||||
|
||||
#include "simulation_structs.hpp"
|
||||
#include "simulationmesh.hpp"
|
||||
#include "utilities.hpp"
|
||||
#include <algorithm>
|
||||
#include <matplot/matplot.h>
|
||||
|
||||
struct SimulationResultsReporter {
|
||||
using VertexType = VCGEdgeMesh::VertexType;
|
||||
using CoordType = VCGEdgeMesh::CoordType;
|
||||
|
||||
SimulationResultsReporter() {}
|
||||
|
||||
void writeStatistics(const SimulationResults &results,
|
||||
const std::string &reportFolderPath) {
|
||||
std::ofstream file;
|
||||
file.open(std::filesystem::path(reportFolderPath).append("results.txt").string());
|
||||
|
||||
const size_t numberOfSteps = results.history.numberOfSteps;
|
||||
file << "Number of steps " << numberOfSteps << "\n";
|
||||
|
||||
// file << "Force threshold used " << 1000 << "\n";
|
||||
|
||||
// assert(numberOfSteps == results.history.potentialEnergy.size() &&
|
||||
// numberOfSteps == results.history.residualForces.size());
|
||||
// Write kinetic energies
|
||||
const SimulationHistory &history = results.history;
|
||||
if (!history.kineticEnergy.empty()) {
|
||||
file << "Kinetic energies"
|
||||
<< "\n";
|
||||
for (size_t step = 0; step < numberOfSteps; step++) {
|
||||
file << history.kineticEnergy[step] << "\n";
|
||||
}
|
||||
file << "\n";
|
||||
}
|
||||
|
||||
if (!history.logResidualForces.empty()) {
|
||||
file << "Residual forces"
|
||||
<< "\n";
|
||||
for (size_t step = 0; step < numberOfSteps; step++) {
|
||||
file << history.logResidualForces[step] << "\n";
|
||||
}
|
||||
file << "\n";
|
||||
}
|
||||
|
||||
if (!history.potentialEnergies.empty()) {
|
||||
file << "Potential energies"
|
||||
<< "\n";
|
||||
for (size_t step = 0; step < numberOfSteps; step++) {
|
||||
file << history.potentialEnergies[step] << "\n";
|
||||
}
|
||||
file << "\n";
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void reportHistory(const SimulationHistory &history,
|
||||
const std::string &reportFolderPath,
|
||||
const std::string &graphSuffix = std::string())
|
||||
{
|
||||
const auto simulationResultPath = std::filesystem::path(reportFolderPath).append(history.label);
|
||||
std::filesystem::create_directories(simulationResultPath);
|
||||
createPlots(history, simulationResultPath.string(), graphSuffix);
|
||||
}
|
||||
|
||||
void reportResults(const std::vector<SimulationResults> &results,
|
||||
const std::string &reportFolderPath,
|
||||
const std::string &graphSuffix = std::string()) {
|
||||
if (results.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// std::filesystem::remove_all(debuggerFolder);
|
||||
std::filesystem::create_directory(reportFolderPath);
|
||||
for (const SimulationResults &simulationResult : results) {
|
||||
const auto simulationResultPath =
|
||||
std::filesystem::path(reportFolderPath)
|
||||
.append(simulationResult.getLabel());
|
||||
std::filesystem::create_directory(simulationResultPath.string());
|
||||
|
||||
createPlots(simulationResult.history, simulationResultPath.string(),
|
||||
graphSuffix);
|
||||
writeStatistics(simulationResult, simulationResultPath.string());
|
||||
}
|
||||
}
|
||||
|
||||
static void createPlot(const std::string &xLabel,
|
||||
const std::string &yLabel,
|
||||
const std::vector<double> &YvaluesToPlot,
|
||||
const std::string &saveTo = {},
|
||||
const std::vector<size_t> &markPoints = {})
|
||||
{
|
||||
if (YvaluesToPlot.size() < 2) {
|
||||
return;
|
||||
}
|
||||
std::vector<double> colors(YvaluesToPlot.size(), 0.5);
|
||||
std::vector<double> markerSizes(YvaluesToPlot.size(), 5);
|
||||
if (!markPoints.empty()) {
|
||||
for (const auto pointIndex : markPoints) {
|
||||
colors[pointIndex] = 0.9;
|
||||
markerSizes[pointIndex] = 14;
|
||||
}
|
||||
}
|
||||
std::vector<double> x = matplot::linspace(0, YvaluesToPlot.size() - 1, YvaluesToPlot.size());
|
||||
Utilities::createPlot(xLabel, yLabel, x, YvaluesToPlot, markerSizes, colors, saveTo);
|
||||
}
|
||||
|
||||
void createPlots(const SimulationHistory &history,
|
||||
const std::string &reportFolderPath,
|
||||
const std::string &graphSuffix)
|
||||
{
|
||||
const auto graphsFolder = std::filesystem::path(reportFolderPath).append("Graphs");
|
||||
std::filesystem::remove_all(graphsFolder);
|
||||
std::filesystem::create_directory(graphsFolder.string());
|
||||
|
||||
if (!history.kineticEnergy.empty()) {
|
||||
createPlot("Number of Iterations",
|
||||
"Log of Kinetic Energy log",
|
||||
history.kineticEnergy,
|
||||
std::filesystem::path(graphsFolder)
|
||||
.append("KineticEnergyLog_" + graphSuffix + ".png")
|
||||
.string(),
|
||||
history.redMarks);
|
||||
}
|
||||
|
||||
if (!history.logResidualForces.empty()) {
|
||||
createPlot("Number of Iterations",
|
||||
"Residual Forces norm log",
|
||||
history.logResidualForces,
|
||||
std::filesystem::path(graphsFolder)
|
||||
.append("ResidualForcesLog_" + graphSuffix + ".png")
|
||||
.string(),
|
||||
history.redMarks);
|
||||
}
|
||||
|
||||
if (!history.potentialEnergies.empty()) {
|
||||
createPlot("Number of Iterations",
|
||||
"Potential energy",
|
||||
history.potentialEnergies,
|
||||
std::filesystem::path(graphsFolder)
|
||||
.append("PotentialEnergy_" + graphSuffix + ".png")
|
||||
.string(),
|
||||
history.redMarks);
|
||||
}
|
||||
if (!history.residualForcesMovingAverage.empty()) {
|
||||
createPlot("Number of Iterations",
|
||||
"Residual forces moving average",
|
||||
history.residualForcesMovingAverage,
|
||||
std::filesystem::path(graphsFolder)
|
||||
.append("ResidualForcesMovingAverage_" + graphSuffix + ".png")
|
||||
.string(),
|
||||
history.redMarks);
|
||||
}
|
||||
// if (!history.residualForcesMovingAverageDerivativesLog.empty()) {
|
||||
// createPlot("Number of Iterations",
|
||||
// "Residual forces moving average derivative log",
|
||||
// history.residualForcesMovingAverageDerivativesLog,
|
||||
// std::filesystem::path(graphsFolder)
|
||||
// .append("ResidualForcesMovingAverageDerivativesLog_" + graphSuffix + ".png")
|
||||
// .string());
|
||||
// }
|
||||
if (!history.perVertexAverageNormalizedDisplacementNorm.empty()) {
|
||||
createPlot("Number of Iterations",
|
||||
"Sum of normalized displacement norms",
|
||||
history.perVertexAverageNormalizedDisplacementNorm,
|
||||
std::filesystem::path(graphsFolder)
|
||||
.append("SumOfNormalizedDisplacementNorms_" + graphSuffix + ".png")
|
||||
.string(),
|
||||
history.redMarks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SIMULATIONHISTORYPLOTTER_HPP
|
|
@ -1,528 +0,0 @@
|
|||
#include "simulationmesh.hpp"
|
||||
//#include <wrap/nanoply/include/nanoplyWrapper.hpp>
|
||||
|
||||
SimulationMesh::SimulationMesh() {
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
|
||||
*this, std::string("Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(
|
||||
*this, std::string("Nodes"));
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(VCGEdgeMesh &mesh) {
|
||||
vcg::tri::MeshAssert<VCGEdgeMesh>::VertexNormalNormalized(mesh);
|
||||
|
||||
VCGEdgeMesh::copy(mesh);
|
||||
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
|
||||
*this, std::string("Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(*this,
|
||||
std::string("Nodes"));
|
||||
initializeNodes();
|
||||
initializeElements();
|
||||
}
|
||||
|
||||
SimulationMesh::~SimulationMesh() {
|
||||
vcg::tri::Allocator<SimulationMesh>::DeletePerEdgeAttribute<Element>(*this,
|
||||
elements);
|
||||
vcg::tri::Allocator<SimulationMesh>::DeletePerVertexAttribute<Node>(*this,
|
||||
nodes);
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(PatternGeometry &pattern) {
|
||||
vcg::tri::MeshAssert<PatternGeometry>::VertexNormalNormalized(pattern);
|
||||
VCGEdgeMesh::copy(pattern);
|
||||
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
|
||||
*this, std::string("Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(
|
||||
*this, std::string("Nodes"));
|
||||
initializeNodes();
|
||||
initializeElements();
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(SimulationMesh &m)
|
||||
{
|
||||
vcg::tri::MeshAssert<SimulationMesh>::VertexNormalNormalized(m);
|
||||
VCGEdgeMesh::copy(m);
|
||||
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(*this,
|
||||
std::string(
|
||||
"Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(*this,
|
||||
std::string("Nodes"));
|
||||
initializeNodes();
|
||||
|
||||
for (size_t ei = 0; ei < EN(); ei++) {
|
||||
elements[ei] = m.elements[ei];
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(VCGTriMesh &triMesh)
|
||||
{
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGTriMesh>::MeshCopy(*this, triMesh);
|
||||
label = triMesh.getLabel();
|
||||
// eigenEdges = triMesh.getEigenEdges();
|
||||
// if (eigenEdges.rows() == 0) {
|
||||
computeEdges(eigenEdges);
|
||||
// }
|
||||
// eigenVertices = triMesh.getEigenVertices();
|
||||
// if (eigenVertices.rows() == 0) {
|
||||
computeVertices(eigenVertices);
|
||||
// }
|
||||
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
|
||||
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(*this,
|
||||
std::string(
|
||||
"Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(*this,
|
||||
std::string("Nodes"));
|
||||
initializeNodes();
|
||||
initializeElements();
|
||||
reset();
|
||||
}
|
||||
|
||||
void SimulationMesh::computeElementalProperties() {
|
||||
const std::vector<CrossSectionType> elementalDimensions = getBeamDimensions();
|
||||
const std::vector<ElementMaterial> elementalMaterials = getBeamMaterial();
|
||||
assert(EN() == elementalDimensions.size() &&
|
||||
elementalDimensions.size() == elementalMaterials.size());
|
||||
|
||||
for (const EdgeType &e : edge) {
|
||||
const EdgeIndex ei = getIndex(e);
|
||||
elements[e].setDimensions(elementalDimensions[ei]);
|
||||
elements[e].setMaterial(elementalMaterials[ei]);
|
||||
}
|
||||
}
|
||||
|
||||
void SimulationMesh::initializeNodes() {
|
||||
// set initial and previous locations,
|
||||
for (const VertexType &v : vert) {
|
||||
const VertexIndex vi = getIndex(v);
|
||||
Node &node = nodes[v];
|
||||
node.vi = vi;
|
||||
node.initialLocation = v.cP();
|
||||
node.initialNormal = v.cN();
|
||||
node.derivativeOfNormal.resize(6, VectorType(0, 0, 0));
|
||||
|
||||
node.displacements[3] =
|
||||
v.cN()[0]; // initialize nx diplacement with vertex normal x
|
||||
// component
|
||||
node.displacements[4] = v.cN()[1]; // initialize ny(in the paper) diplacement with vertex
|
||||
// normal
|
||||
// y component.
|
||||
|
||||
// Initialize incident elements
|
||||
std::vector<VCGEdgeMesh::EdgePointer> incidentElements;
|
||||
vcg::edge::VEStarVE(&v, incidentElements);
|
||||
// assert(
|
||||
// vcg::tri::IsValidPointer<SimulationMesh>(*this, incidentElements[0]) &&
|
||||
// incidentElements.size() > 0);
|
||||
if (incidentElements.size() != 0) {
|
||||
nodes[v].incidentElements = incidentElements;
|
||||
node.referenceElement = getReferenceElement(v);
|
||||
// std::vector<int> incidentElementsIndices(node.incidentElements.size());
|
||||
// if (drawGlobal && vi == 5) {
|
||||
// std::vector<glm::vec3> edgeColors(EN(), glm::vec3(0, 1, 0));
|
||||
// std::vector<glm::vec3> vertexColors(VN(), glm::vec3(0, 1, 0));
|
||||
// vertexColors[vi] = glm::vec3(0, 0, 1);
|
||||
// for (int iei = 0; iei < incidentElementsIndices.size(); iei++) {
|
||||
// incidentElementsIndices[iei] = this->getIndex(node.incidentElements[iei]);
|
||||
// edgeColors[incidentElementsIndices[iei]] = glm::vec3(1, 0, 0);
|
||||
// }
|
||||
// polyHandle->addEdgeColorQuantity("chosenE", edgeColors)->setEnabled(true);
|
||||
// polyHandle->addNodeColorQuantity("chosenV", vertexColors)->setEnabled(true);
|
||||
// draw();
|
||||
// }
|
||||
// const int referenceElementIndex = getIndex(node.referenceElement);
|
||||
// Initialze alpha angles
|
||||
|
||||
const EdgeType &referenceElement = *node.referenceElement;
|
||||
const VectorType t01 = computeT1Vector(referenceElement.cP(0), referenceElement.cP(1));
|
||||
const VectorType f01 = (t01 - (v.cN() * (t01.dot(v.cN())))).Normalize();
|
||||
node.alphaAngles.reserve(incidentElements.size());
|
||||
|
||||
for (const VCGEdgeMesh::EdgePointer &ep : nodes[v].incidentElements) {
|
||||
assert(referenceElement.cV(0) == ep->cV(0) || referenceElement.cV(0) == ep->cV(1)
|
||||
|| referenceElement.cV(1) == ep->cV(0) || referenceElement.cV(1) == ep->cV(1));
|
||||
const VectorType t1 = computeT1Vector(*ep);
|
||||
const VectorType f1 = t1 - (v.cN() * (t1.dot(v.cN()))).Normalize();
|
||||
const EdgeIndex ei = getIndex(ep);
|
||||
const double alphaAngle = computeAngle(f01, f1, v.cN());
|
||||
node.alphaAngles.emplace_back(std::make_pair(ei, alphaAngle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimulationMesh::reset() {
|
||||
for (const EdgeType &e : edge) {
|
||||
Element &element = elements[e];
|
||||
element.ei = getIndex(e);
|
||||
const VCGEdgeMesh::CoordType p0 = e.cP(0);
|
||||
const VCGEdgeMesh::CoordType p1 = e.cP(1);
|
||||
const vcg::Segment3<double> s(p0, p1);
|
||||
element.initialLength = s.Length();
|
||||
element.length = element.initialLength;
|
||||
element.updateRigidity();
|
||||
}
|
||||
|
||||
for (const VertexType &v : vert) {
|
||||
Node &node = nodes[v];
|
||||
node.vi = getIndex(v);
|
||||
node.initialLocation = v.cP();
|
||||
node.initialNormal = v.cN();
|
||||
node.derivativeOfNormal.resize(6, VectorType(0, 0, 0));
|
||||
|
||||
node.displacements[3] = v.cN()[0]; // initialize nx diplacement with vertex normal x
|
||||
// component
|
||||
node.displacements[4] = v.cN()[1]; // initialize ny(in the paper) diplacement with vertex
|
||||
// normal
|
||||
// y component.
|
||||
|
||||
const EdgeType &referenceElement = *getReferenceElement(v);
|
||||
const VectorType t01 = computeT1Vector(referenceElement.cP(0), referenceElement.cP(1));
|
||||
const VectorType f01 = (t01 - (v.cN() * (t01.dot(v.cN())))).Normalize();
|
||||
node.alphaAngles.clear();
|
||||
node.alphaAngles.reserve(node.incidentElements.size());
|
||||
for (const VCGEdgeMesh::EdgePointer &ep : nodes[v].incidentElements) {
|
||||
assert(referenceElement.cV(0) == ep->cV(0) || referenceElement.cV(0) == ep->cV(1)
|
||||
|| referenceElement.cV(1) == ep->cV(0) || referenceElement.cV(1) == ep->cV(1));
|
||||
const VectorType t1 = computeT1Vector(*ep);
|
||||
const VectorType f1 = t1 - (v.cN() * (t1.dot(v.cN()))).Normalize();
|
||||
const EdgeIndex ei = getIndex(ep);
|
||||
const double alphaAngle = computeAngle(f01, f1, v.cN());
|
||||
node.alphaAngles.emplace_back(std::make_pair(ei, alphaAngle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimulationMesh::initializeElements() {
|
||||
for (const EdgeType &e : edge) {
|
||||
Element &element = elements[e];
|
||||
element.ei = getIndex(e);
|
||||
// Initialize dimensions
|
||||
element.dimensions = CrossSectionType();
|
||||
// Initialize material
|
||||
element.material = ElementMaterial();
|
||||
// Initialize lengths
|
||||
const VCGEdgeMesh::CoordType p0 = e.cP(0);
|
||||
const VCGEdgeMesh::CoordType p1 = e.cP(1);
|
||||
const vcg::Segment3<double> s(p0, p1);
|
||||
element.initialLength = s.Length();
|
||||
element.length = element.initialLength;
|
||||
// Initialize const factors
|
||||
element.updateRigidity();
|
||||
element.derivativeT1.resize(
|
||||
2, std::vector<VectorType>(6, VectorType(0, 0, 0)));
|
||||
element.derivativeT2.resize(
|
||||
2, std::vector<VectorType>(6, VectorType(0, 0, 0)));
|
||||
element.derivativeT3.resize(
|
||||
2, std::vector<VectorType>(6, VectorType(0, 0, 0)));
|
||||
element.derivativeT1_jplus1.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeT1_j.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeT1_jplus1.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeT2_j.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeT2_jplus1.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeT3_j.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeT3_jplus1.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeR_j.resize(6, VectorType(0, 0, 0));
|
||||
element.derivativeR_jplus1.resize(6, VectorType(0, 0, 0));
|
||||
}
|
||||
updateElementalFrames();
|
||||
}
|
||||
|
||||
void SimulationMesh::updateElementalLengths() {
|
||||
for (const EdgeType &e : edge) {
|
||||
const EdgeIndex ei = getIndex(e);
|
||||
const VertexIndex vi0 = getIndex(e.cV(0));
|
||||
const VCGEdgeMesh::CoordType p0 = e.cP(0);
|
||||
const VertexIndex vi1 = getIndex(e.cV(1));
|
||||
const VCGEdgeMesh::CoordType p1 = e.cP(1);
|
||||
const vcg::Segment3<double> s(p0, p1);
|
||||
const double elementLength = s.Length();
|
||||
elements[e].length = elementLength;
|
||||
}
|
||||
}
|
||||
|
||||
void SimulationMesh::updateElementalFrames() {
|
||||
for (const EdgeType &e : edge) {
|
||||
const VectorType elementNormal =
|
||||
(e.cV(0)->cN() + e.cV(1)->cN()).Normalize();
|
||||
elements[e].frame = computeElementFrame(e.cP(0), e.cP(1), elementNormal);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
polyscope::CurveNetwork *SimulationMesh::registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor, const bool &shouldEnable)
|
||||
{
|
||||
const double drawingRadius = getBeamDimensions()[0].getDrawingRadius();
|
||||
// std::cout << __FUNCTION__ << " revert this" << std::endl;
|
||||
return VCGEdgeMesh::registerForDrawing(desiredColor, /*0.08*/ drawingRadius, shouldEnable);
|
||||
}
|
||||
|
||||
void SimulationMesh::unregister() const
|
||||
{
|
||||
VCGEdgeMesh::unregister();
|
||||
}
|
||||
#endif
|
||||
|
||||
void SimulationMesh::setBeamCrossSection(const CrossSectionType &beamDimensions)
|
||||
{
|
||||
for (size_t ei = 0; ei < EN(); ei++) {
|
||||
elements[ei].dimensions = beamDimensions;
|
||||
elements[ei].updateRigidity();
|
||||
}
|
||||
}
|
||||
|
||||
void SimulationMesh::setBeamMaterial(const double &pr, const double &ym) {
|
||||
for (size_t ei = 0; ei < EN(); ei++) {
|
||||
elements[ei].setMaterial(ElementMaterial{pr, ym});
|
||||
elements[ei].updateRigidity();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CrossSectionType> SimulationMesh::getBeamDimensions()
|
||||
{
|
||||
std::vector<CrossSectionType> beamDimensions(EN());
|
||||
for (size_t ei = 0; ei < EN(); ei++) {
|
||||
beamDimensions[ei] = elements[ei].dimensions;
|
||||
}
|
||||
return beamDimensions;
|
||||
}
|
||||
|
||||
std::vector<ElementMaterial> SimulationMesh::getBeamMaterial()
|
||||
{
|
||||
std::vector<ElementMaterial> beamMaterial(EN());
|
||||
for (size_t ei = 0; ei < EN(); ei++) {
|
||||
beamMaterial[ei] = elements[ei].material;
|
||||
}
|
||||
return beamMaterial;
|
||||
}
|
||||
|
||||
bool SimulationMesh::load(const std::string &plyFilename)
|
||||
{
|
||||
this->Clear();
|
||||
// assert(plyFileHasAllRequiredFields(plyFilename));
|
||||
// Load the ply file
|
||||
// VCGEdgeMesh::PerEdgeAttributeHandle<CrossSectionType> handleBeamDimensions =
|
||||
// vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute<
|
||||
// CrossSectionType>(*this, plyPropertyBeamDimensionsID);
|
||||
// VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial> handleBeamMaterial =
|
||||
// vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute<ElementMaterial>(
|
||||
// *this, plyPropertyBeamMaterialID);
|
||||
// nanoply::NanoPlyWrapper<SimulationMesh>::CustomAttributeDescriptor
|
||||
// customAttrib;
|
||||
// customAttrib.GetMeshAttrib(plyFilename);
|
||||
// customAttrib.AddEdgeAttribDescriptor<CrossSectionType, double, 2>(
|
||||
// plyPropertyBeamDimensionsID, nanoply::NNP_LIST_INT8_FLOAT64, nullptr);
|
||||
// /*FIXME: Since I allow CrossSectionType to take two types I should export the
|
||||
// * type as well such that that when loaded the correct type of cross section
|
||||
// * is used.
|
||||
// */
|
||||
// customAttrib.AddEdgeAttribDescriptor<vcg::Point2d, double, 2>(
|
||||
// plyPropertyBeamMaterialID, nanoply::NNP_LIST_INT8_FLOAT64, nullptr);
|
||||
|
||||
// VCGEdgeMesh::PerEdgeAttributeHandle<std::array<double, 6>>
|
||||
// handleBeamProperties =
|
||||
// vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute<
|
||||
// std::array<double, 6>>(*this, plyPropertyBeamProperties);
|
||||
// customAttrib.AddEdgeAttribDescriptor<std::array<double, 6>, double, 6>(
|
||||
// plyPropertyBeamProperties, nanoply::NNP_LIST_INT8_FLOAT64, nullptr);
|
||||
|
||||
// VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial>
|
||||
// handleBeamRigidityContants;
|
||||
// customAttrib.AddEdgeAttribDescriptor<vcg::Point4f, float, 4>(
|
||||
// plyPropertyBeamRigidityConstantsID, nanoply::NNP_LIST_INT8_FLOAT32,
|
||||
// nullptr);
|
||||
// unsigned int mask = 0;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_MESHATTRIB;
|
||||
if (!VCGEdgeMesh::load(plyFilename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
|
||||
// *this, std::string("Elements"));
|
||||
// nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(
|
||||
// *this, std::string("Nodes"));
|
||||
vcg::tri::UpdateTopology<SimulationMesh>::VertexEdge(*this);
|
||||
initializeNodes();
|
||||
initializeElements();
|
||||
setBeamMaterial(0.3, 1 * 1e9);
|
||||
updateEigenEdgeAndVertices();
|
||||
|
||||
// if (!handleBeamProperties._handle->data.empty()) {
|
||||
// for (size_t ei = 0; ei < EN(); ei++) {
|
||||
// elements[ei] =
|
||||
// Element::Properties(handleBeamProperties[ei]);
|
||||
// elements[ei].updateRigidity();
|
||||
// }
|
||||
// }
|
||||
// for (size_t ei = 0; ei < EN(); ei++) {
|
||||
// elements[ei].setDimensions(handleBeamDimensions[ei]);
|
||||
// elements[ei].setMaterial(handleBeamMaterial[ei]);
|
||||
// elements[ei].updateRigidity();
|
||||
// }
|
||||
|
||||
bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001;
|
||||
if (normalsAreAbsent) {
|
||||
CoordType normalVector(0, 0, 1);
|
||||
std::cout << "Warning: Normals are missing from " << plyFilename
|
||||
<< ". Added normal vector:" << toString(normalVector) << std::endl;
|
||||
for (auto &v : vert) {
|
||||
v.N() = normalVector;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimulationMesh::save(const std::string &plyFilename)
|
||||
{
|
||||
std::string filename = plyFilename;
|
||||
if (filename.empty()) {
|
||||
filename = std::filesystem::current_path().append(getLabel() + ".ply").string();
|
||||
}
|
||||
// nanoply::NanoPlyWrapper<VCGEdgeMesh>::CustomAttributeDescriptor customAttrib;
|
||||
// customAttrib.GetMeshAttrib(filename);
|
||||
|
||||
// std::vector<CrossSectionType> dimensions = getBeamDimensions();
|
||||
// customAttrib.AddEdgeAttribDescriptor<CrossSectionType, double, 2>(plyPropertyBeamDimensionsID,
|
||||
// nanoply::NNP_LIST_INT8_FLOAT64,
|
||||
// dimensions.data());
|
||||
// std::vector<ElementMaterial> material = getBeamMaterial();
|
||||
// customAttrib.AddEdgeAttribDescriptor<vcg::Point2d, double, 2>(plyPropertyBeamMaterialID,
|
||||
// nanoply::NNP_LIST_INT8_FLOAT64,
|
||||
// material.data());
|
||||
// unsigned int mask = 0;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB;
|
||||
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
|
||||
// if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::SaveModel(filename.c_str(),
|
||||
// *this,
|
||||
// mask,
|
||||
// customAttrib,
|
||||
// false)
|
||||
// != 1) {
|
||||
// return false;
|
||||
// }
|
||||
if (!VCGEdgeMesh::save(plyFilename)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SimulationMesh::EdgePointer
|
||||
SimulationMesh::getReferenceElement(const VCGEdgeMesh::VertexType &v) {
|
||||
const VertexIndex vi = getIndex(v);
|
||||
return nodes[v].incidentElements[0];
|
||||
}
|
||||
|
||||
VectorType computeT1Vector(const SimulationMesh::EdgeType &e)
|
||||
{
|
||||
return computeT1Vector(e.cP(0), e.cP(1));
|
||||
}
|
||||
|
||||
VectorType computeT1Vector(const CoordType &p0, const CoordType &p1) {
|
||||
const VectorType t1 = (p1 - p0).Normalize();
|
||||
return t1;
|
||||
}
|
||||
|
||||
Element::LocalFrame computeElementFrame(const CoordType &p0,
|
||||
const CoordType &p1,
|
||||
const VectorType &elementNormal) {
|
||||
const VectorType t1 = computeT1Vector(p0, p1);
|
||||
const VectorType t2 = (elementNormal ^ t1).Normalize();
|
||||
const VectorType t3 = (t1 ^ t2).Normalize();
|
||||
|
||||
return Element::LocalFrame{t1, t2, t3};
|
||||
}
|
||||
|
||||
double computeAngle(const VectorType &vector0, const VectorType &vector1,
|
||||
const VectorType &normalVector) {
|
||||
double cosAngle = vector0.dot(vector1);
|
||||
const double epsilon = std::pow(10, -6);
|
||||
if (abs(cosAngle) > 1 && abs(cosAngle) < 1 + epsilon) {
|
||||
if (cosAngle > 0) {
|
||||
cosAngle = 1;
|
||||
|
||||
} else {
|
||||
cosAngle = -1;
|
||||
}
|
||||
}
|
||||
assert(abs(cosAngle) <= 1);
|
||||
const double angle =
|
||||
acos(cosAngle); // NOTE: I compute the alpha angle not between
|
||||
// two consecutive elements but rather between
|
||||
// the first and the ith. Is this correct?
|
||||
assert(!std::isnan(angle));
|
||||
|
||||
const VectorType cp = vector0 ^ vector1;
|
||||
if (cp.dot(normalVector) < 0) {
|
||||
return -angle;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
//void Element::computeMaterialProperties(const ElementMaterial &material) {
|
||||
// G = material.youngsModulus / (2 * (1 + material.poissonsRatio));
|
||||
//}
|
||||
|
||||
//void Element::computeCrossSectionArea(const RectangularBeamDimensions &dimensions, double &A)
|
||||
//{
|
||||
// A = dimensions.b * dimensions.h;
|
||||
//}
|
||||
|
||||
//void Element::computeDimensionsProperties(
|
||||
// const RectangularBeamDimensions &dimensions) {
|
||||
// assert(typeid(CrossSectionType) == typeid(RectangularBeamDimensions));
|
||||
// computeCrossSectionArea(dimensions, A);
|
||||
// computeMomentsOfInertia(dimensions, dimensions.inertia);
|
||||
//}
|
||||
|
||||
//void Element::computeDimensionsProperties(
|
||||
// const CylindricalBeamDimensions &dimensions) {
|
||||
// assert(typeid(CrossSectionType) == typeid(CylindricalBeamDimensions));
|
||||
// A = M_PI * (std::pow(dimensions.od / 2, 2) - std::pow(dimensions.id / 2, 2));
|
||||
// dimensions.inertia.I2 = M_PI * (std::pow(dimensions.od, 4) - std::pow(dimensions.id, 4)) / 64;
|
||||
// dimensions.inertia.I3 = dimensions.inertia.I2;
|
||||
// dimensions.inertia.J = dimensions.inertia.I2 + dimensions.inertia.I3;
|
||||
//}
|
||||
|
||||
void Element::setDimensions(const CrossSectionType &dimensions) {
|
||||
this->dimensions = dimensions;
|
||||
assert(this->dimensions.A == dimensions.A);
|
||||
// computeDimensionsProperties(dimensions);
|
||||
updateRigidity();
|
||||
}
|
||||
|
||||
void Element::setMaterial(const ElementMaterial &material)
|
||||
{
|
||||
this->material = material;
|
||||
// computeMaterialProperties(material);
|
||||
updateRigidity();
|
||||
}
|
||||
|
||||
double Element::getMass(const double &materialDensity)
|
||||
{
|
||||
const double beamVolume = dimensions.A * length;
|
||||
return beamVolume * materialDensity;
|
||||
}
|
||||
|
||||
void Element::updateRigidity() {
|
||||
// assert(initialLength != 0);
|
||||
rigidity.axial = material.youngsModulus * dimensions.A / initialLength;
|
||||
// assert(rigidity.axial != 0);
|
||||
rigidity.torsional = material.G * dimensions.inertia.J / initialLength;
|
||||
// assert(rigidity.torsional != 0);
|
||||
rigidity.firstBending = 2 * material.youngsModulus * dimensions.inertia.I2 / initialLength;
|
||||
// assert(rigidity.firstBending != 0);
|
||||
rigidity.secondBending = 2 * material.youngsModulus * dimensions.inertia.I3 / initialLength;
|
||||
// assert(rigidity.secondBending != 0);
|
||||
}
|
|
@ -1,198 +0,0 @@
|
|||
#ifndef SIMULATIONMESH_HPP
|
||||
#define SIMULATIONMESH_HPP
|
||||
|
||||
#include "edgemesh.hpp"
|
||||
#include "trianglepatterngeometry.hpp"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
//extern bool drawGlobal;
|
||||
struct Element;
|
||||
struct Node;
|
||||
//using CrossSectionType = RectangularBeamDimensions;
|
||||
using CrossSectionType = CylindricalBeamDimensions;
|
||||
|
||||
class SimulationMesh : public VCGEdgeMesh {
|
||||
private:
|
||||
void computeElementalProperties();
|
||||
void initializeElements();
|
||||
void initializeNodes();
|
||||
EdgePointer getReferenceElement(const VertexType &v);
|
||||
|
||||
const std::string plyPropertyBeamDimensionsID{"beam_dimensions"};
|
||||
const std::string plyPropertyBeamMaterialID{"beam_material"};
|
||||
|
||||
public:
|
||||
PerEdgeAttributeHandle<Element> elements;
|
||||
PerVertexAttributeHandle<Node> nodes;
|
||||
~SimulationMesh();
|
||||
SimulationMesh(PatternGeometry &pattern);
|
||||
SimulationMesh(ConstVCGEdgeMesh &edgeMesh);
|
||||
SimulationMesh(SimulationMesh &elementalMesh);
|
||||
SimulationMesh(VCGTriMesh &triMesh);
|
||||
void updateElementalLengths();
|
||||
void updateIncidentElements();
|
||||
|
||||
std::vector<VCGEdgeMesh::EdgePointer>
|
||||
getIncidentElements(const VCGEdgeMesh::VertexType &v);
|
||||
virtual bool load(const std::string &plyFilename);
|
||||
std::vector<CrossSectionType> getBeamDimensions();
|
||||
std::vector<ElementMaterial> getBeamMaterial();
|
||||
|
||||
double pre_previousTotalKineticEnergy{0};
|
||||
double pre_previousTotalTranslationalKineticEnergy{0};
|
||||
double pre_previousTotalRotationalKineticEnergy{0};
|
||||
double previousTotalKineticEnergy{0};
|
||||
double previousTotalTranslationalKineticEnergy{0};
|
||||
double previousTotalRotationalKineticEnergy{0};
|
||||
double previousTotalResidualForcesNorm{0};
|
||||
double currentTotalKineticEnergy{0};
|
||||
double currentTotalTranslationalKineticEnergy{0};
|
||||
double currentTotalRotationalKineticEnergy{0};
|
||||
double totalResidualForcesNorm{0};
|
||||
double totalExternalForcesNorm{0};
|
||||
double averageResidualForcesNorm{0};
|
||||
double currentTotalPotentialEnergykN{0};
|
||||
double previousTotalPotentialEnergykN{0};
|
||||
double residualForcesMovingAverageDerivativeNorm{0};
|
||||
double residualForcesMovingAverage{0};
|
||||
double perVertexAverageNormalizedDisplacementNorm{0};
|
||||
bool save(const std::string &plyFilename = std::string());
|
||||
void setBeamCrossSection(const CrossSectionType &beamDimensions);
|
||||
void setBeamMaterial(const double &pr, const double &ym);
|
||||
void reset();
|
||||
SimulationMesh();
|
||||
void updateElementalFrames();
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
polyscope::CurveNetwork *registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor = std::nullopt,
|
||||
const bool &shouldEnable = true);
|
||||
void unregister() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Element
|
||||
{
|
||||
CrossSectionType dimensions;
|
||||
ElementMaterial material;
|
||||
|
||||
void computeMaterialProperties(const ElementMaterial &material);
|
||||
// void computeDimensionsProperties(const RectangularBeamDimensions &dimensions);
|
||||
// void computeDimensionsProperties(const CylindricalBeamDimensions &dimensions);
|
||||
void setDimensions(const CrossSectionType &dimensions);
|
||||
void setMaterial(const ElementMaterial &material);
|
||||
double getMass(const double &matrialDensity);
|
||||
|
||||
struct LocalFrame
|
||||
{
|
||||
VectorType t1;
|
||||
VectorType t2;
|
||||
VectorType t3;
|
||||
};
|
||||
|
||||
EdgeIndex ei;
|
||||
double length{0};
|
||||
double initialLength;
|
||||
LocalFrame frame;
|
||||
|
||||
struct Rigidity
|
||||
{
|
||||
double axial;
|
||||
double torsional;
|
||||
double firstBending;
|
||||
double secondBending;
|
||||
std::string toString() const
|
||||
{
|
||||
return std::string("Rigidity:") + std::string("\nAxial=") + std::to_string(axial)
|
||||
+ std::string("\nTorsional=") + std::to_string(torsional)
|
||||
+ std::string("\nFirstBending=") + std::to_string(firstBending)
|
||||
+ std::string("\nSecondBending=") + std::to_string(secondBending);
|
||||
}
|
||||
};
|
||||
Rigidity rigidity;
|
||||
void updateRigidity();
|
||||
|
||||
VectorType f1_j;
|
||||
VectorType f1_jplus1;
|
||||
VectorType f2_j;
|
||||
VectorType f2_jplus1;
|
||||
VectorType f3_j;
|
||||
VectorType f3_jplus1;
|
||||
double cosRotationAngle_j;
|
||||
double cosRotationAngle_jplus1;
|
||||
double sinRotationAngle_j;
|
||||
double sinRotationAngle_jplus1;
|
||||
std::vector<std::vector<VectorType>> derivativeT1;
|
||||
std::vector<std::vector<VectorType>> derivativeT2;
|
||||
std::vector<std::vector<VectorType>> derivativeT3;
|
||||
std::vector<VectorType> derivativeT1_j;
|
||||
std::vector<VectorType> derivativeT1_jplus1;
|
||||
std::vector<VectorType> derivativeT2_j;
|
||||
std::vector<VectorType> derivativeT2_jplus1;
|
||||
std::vector<VectorType> derivativeT3_j;
|
||||
std::vector<VectorType> derivativeT3_jplus1;
|
||||
std::vector<VectorType> derivativeR_j;
|
||||
std::vector<VectorType> derivativeR_jplus1;
|
||||
struct RotationalDisplacements
|
||||
{
|
||||
double theta1{0}, theta2{0}, theta3{0};
|
||||
};
|
||||
RotationalDisplacements rotationalDisplacements_j;
|
||||
RotationalDisplacements rotationalDisplacements_jplus1;
|
||||
|
||||
static void computeCrossSectionArea(const RectangularBeamDimensions &dimensions, double &A);
|
||||
};
|
||||
|
||||
struct Node {
|
||||
struct Forces {
|
||||
Vector6d external{0};
|
||||
Vector6d internal{0};
|
||||
Vector6d residual{0};
|
||||
Vector6d internalAxial{0};
|
||||
Vector6d internalTorsion{0};
|
||||
Vector6d internalFirstBending{0};
|
||||
Vector6d internalSecondBending{0};
|
||||
bool hasExternalForce() const { return external.isZero(); }
|
||||
};
|
||||
|
||||
struct Mass {
|
||||
double translational;
|
||||
double rotationalI2;
|
||||
double rotationalI3;
|
||||
double rotationalJ;
|
||||
};
|
||||
|
||||
Mass mass;
|
||||
Vector6d mass_6d;
|
||||
Vector6d damping_6d;
|
||||
VertexIndex vi;
|
||||
CoordType initialLocation;
|
||||
CoordType initialNormal;
|
||||
Vector6d acceleration{0};
|
||||
Forces force;
|
||||
Vector6d previousVelocity{0};
|
||||
Vector6d velocity{0};
|
||||
double kineticEnergy{0};
|
||||
Vector6d displacements{0};
|
||||
double nR{0};
|
||||
// std::unordered_map<EdgeIndex, double>
|
||||
// alphaAngles; // contains the initial angles between the first star element
|
||||
// // incident to this node and the other elements of the star
|
||||
// // has size equal to the valence of the vertex
|
||||
std::vector<std::pair<EdgeIndex, double>> alphaAngles;
|
||||
|
||||
std::vector<VCGEdgeMesh::EdgePointer> incidentElements;
|
||||
std::vector<VectorType> derivativeOfNormal;
|
||||
SimulationMesh::EdgePointer referenceElement;
|
||||
};
|
||||
|
||||
Element::LocalFrame computeElementFrame(const CoordType &p0,
|
||||
const CoordType &p1,
|
||||
const VectorType &elementNormal);
|
||||
VectorType computeT1Vector(const SimulationMesh::EdgeType &e);
|
||||
|
||||
VectorType computeT1Vector(const CoordType &p0, const CoordType &p1);
|
||||
double computeAngle(const VectorType &vector0, const VectorType &vector1,
|
||||
const VectorType &normalVector);
|
||||
|
||||
#endif // ELEMENTALMESH_HPP
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef SIMULATIONMODEL_HPP
|
||||
#define SIMULATIONMODEL_HPP
|
||||
|
||||
#include "simulation_structs.hpp"
|
||||
|
||||
class SimulationModel
|
||||
{
|
||||
public:
|
||||
virtual SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &simulationJob)
|
||||
= 0;
|
||||
virtual void setStructure(const std::shared_ptr<SimulationMesh> &pMesh) = 0;
|
||||
virtual ~SimulationModel() = default;
|
||||
};
|
||||
|
||||
#endif // SIMULATIONMODEL_HPP
|
108
utilities.cpp
108
utilities.cpp
|
@ -1,108 +0,0 @@
|
|||
#include "utilities.hpp"
|
||||
#include "matplot/matplot.h"
|
||||
|
||||
void Utilities::createPlot(const std::string &xLabel,
|
||||
const std::string &yLabel,
|
||||
const std::vector<double> &x,
|
||||
const std::vector<double> &y,
|
||||
const std::vector<double> &markerSizes,
|
||||
const std::vector<double> &c,
|
||||
const std::string &saveTo)
|
||||
{
|
||||
// matplot::figure(true);
|
||||
matplot::xlabel(xLabel);
|
||||
matplot::ylabel(yLabel);
|
||||
matplot::grid(matplot::on);
|
||||
matplot::scatter(x, y, markerSizes, c)->marker_face(true);
|
||||
if (!saveTo.empty()) {
|
||||
matplot::save(saveTo);
|
||||
}
|
||||
}
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include "polyscope/curve_network.h"
|
||||
#include "polyscope/pick.h"
|
||||
#include "polyscope/polyscope.h"
|
||||
#include <functional>
|
||||
|
||||
void PolyscopeInterface::mainCallback()
|
||||
{
|
||||
ImGui::PushItemWidth(100); // Make ui elements 100 pixels wide,
|
||||
// instead of full width. Must have
|
||||
// matching PopItemWidth() below.
|
||||
|
||||
for (std::function<void()> &userCallback : globalPolyscopeData.userCallbacks) {
|
||||
userCallback();
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
void PolyscopeInterface::addUserCallback(const std::function<void()> &userCallback)
|
||||
{
|
||||
globalPolyscopeData.userCallbacks.push_back(userCallback);
|
||||
}
|
||||
|
||||
void PolyscopeInterface::deinitPolyscope()
|
||||
{
|
||||
if (!polyscope::state::initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
polyscope::render::engine->shutdownImGui();
|
||||
}
|
||||
|
||||
void PolyscopeInterface::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;
|
||||
}
|
||||
|
||||
std::pair<PolyscopeInterface::PolyscopeLabel, size_t> PolyscopeInterface::getSelection()
|
||||
{
|
||||
std::pair<polyscope::Structure *, size_t> selection = polyscope::pick::getSelection();
|
||||
if (selection.first == nullptr) {
|
||||
return std::make_pair(std::string(), 0);
|
||||
}
|
||||
return std::make_pair(selection.first->name, selection.second);
|
||||
}
|
||||
|
||||
void PolyscopeInterface::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);
|
||||
}
|
||||
|
||||
#endif
|
409
utilities.hpp
409
utilities.hpp
|
@ -1,409 +0,0 @@
|
|||
#ifndef UTILITIES_H
|
||||
#define UTILITIES_H
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <regex>
|
||||
#include <string_view>
|
||||
|
||||
#define GET_VARIABLE_NAME(Variable) (#Variable)
|
||||
|
||||
struct Vector6d : public std::array<double, 6> {
|
||||
Vector6d() {
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
this->operator[](i) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Vector6d(const std::vector<double> &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<double, 6> &arr) : std::array<double, 6>(arr) {}
|
||||
|
||||
Vector6d(const std::initializer_list<double> &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 {
|
||||
template<typename T>
|
||||
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();
|
||||
}
|
||||
|
||||
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<typename InputIt>
|
||||
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<std::string> split(const std::string& text, std::string delim)
|
||||
{
|
||||
std::vector<std::string> 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<std::vector<int>> &vv)
|
||||
{
|
||||
std::string s;
|
||||
s.append("{");
|
||||
for (const std::vector<int> &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<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]);
|
||||
});
|
||||
}
|
||||
|
||||
inline Eigen::MatrixXd toEigenMatrix(const std::vector<Vector6d> &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<Vector6d> fromEigenMatrix(const Eigen::MatrixXd &m)
|
||||
{
|
||||
std::vector<Vector6d> 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)
|
||||
{
|
||||
assert(std::filesystem::exists(folderPath));
|
||||
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 "";
|
||||
}
|
||||
|
||||
void createPlot(const std::string &xLabel,
|
||||
const std::string &yLabel,
|
||||
const std::vector<double> &x,
|
||||
const std::vector<double> &y,
|
||||
const std::vector<double> &markerSizes,
|
||||
const std::vector<double> &c,
|
||||
const std::string &saveTo = {});
|
||||
|
||||
} // namespace Utilities
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
|
||||
namespace PolyscopeInterface {
|
||||
inline struct GlobalPolyscopeData
|
||||
{
|
||||
std::vector<std::function<void()>> userCallbacks;
|
||||
} globalPolyscopeData;
|
||||
|
||||
void mainCallback();
|
||||
|
||||
void addUserCallback(const std::function<void()> &userCallback);
|
||||
|
||||
void deinitPolyscope();
|
||||
|
||||
void init();
|
||||
using PolyscopeLabel = std::string;
|
||||
std::pair<PolyscopeLabel, size_t> getSelection();
|
||||
|
||||
void registerWorldAxes();
|
||||
} // namespace PolyscopeInterface
|
||||
|
||||
#endif
|
||||
|
||||
// namespace ConfigurationFile {
|
||||
|
||||
//}
|
||||
//} // namespace ConfigurationFile
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> std::string toString(const T &v) {
|
||||
return "(" + std::to_string(v[0]) + "," + std::to_string(v[1]) + "," +
|
||||
std::to_string(v[2]) + ")";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t computeHashUnordered(const std::vector<T> &v)
|
||||
{
|
||||
size_t hash = 0;
|
||||
for (const auto &el : v) {
|
||||
hash += std::hash<T>{}(el);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
inline size_t computeHashOrdered(const std::vector<int> &v)
|
||||
{
|
||||
std::string elementsString;
|
||||
for (const auto &el : v) {
|
||||
elementsString += std::to_string(el);
|
||||
}
|
||||
|
||||
return std::hash<std::string>{}(elementsString);
|
||||
}
|
||||
|
||||
#endif // UTILITIES_H
|
Loading…
Reference in New Issue