Compare commits
5 Commits
reducedOpt
...
master
Author | SHA1 | Date |
---|---|---|
|
07d21cc575 | |
|
c5150a2e14 | |
|
5fe427ab2d | |
|
dc5c66b9c6 | |
|
5c4172a949 |
291
CMakeLists.txt
291
CMakeLists.txt
|
@ -1,13 +1,12 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
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,236 +18,108 @@ if(NOT EXISTS ${EXTERNAL_DEPS_DIR})
|
|||
endif()
|
||||
##Create directory for the external libraries
|
||||
file(MAKE_DIRECTORY ${EXTERNAL_DEPS_DIR})
|
||||
|
||||
set(DRMSimulationModelDir "/home/iason/Coding/Libraries/DRMSimulationModel")
|
||||
set(DRMSimulationModelBuildDir ${CMAKE_BINARY_DIR}/_deps)
|
||||
add_subdirectory(${DRMSimulationModelDir} ${DRMSimulationModelBuildDir})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC DRMSimulationModel_lib)
|
||||
#target_include_directories(${PROJECT_NAME} PUBLIC DRMSimulationModel_)
|
||||
|
||||
#target_sources(${PROJECT_NAME} PUBLIC ${DRMSimulationModelDir}/simulationmodel.hpp)
|
||||
if(${USE_DLIB})
|
||||
FetchContent_Declare(dlib
|
||||
GIT_REPOSITORY https://github.com/davisking/dlib.git
|
||||
if(${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
|
||||
)
|
||||
FetchContent_MakeAvailable(dlib)
|
||||
#add_subdirectory(${DLIB_SOURCE_DIR} ${DLIB_BIN_DIR})
|
||||
if(${MYSOURCES_STATIC_LINK})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -static dlib::dlib)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dlib::dlib)
|
||||
endif()
|
||||
add_compile_definitions(DLIB_DEFINED)
|
||||
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)
|
||||
endif()
|
||||
|
||||
## polyscope
|
||||
if(#[[NOT TARGET polyscope AND]] ${USE_POLYSCOPE})
|
||||
message("Using polyscope")
|
||||
FetchContent_Declare(polyscope
|
||||
GIT_REPOSITORY https://github.com/nmwsharp/polyscope.git
|
||||
GIT_TAG master
|
||||
)
|
||||
FetchContent_MakeAvailable(polyscope)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${polyscope_SOURCE_DIR}/include)
|
||||
# target_include_directories(${PROJECT_NAME} PUBLIC ${polyscope_SOURCE_DIR}/deps/imgui)
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${polyscope_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.h ${polyscope_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC polyscope)
|
||||
endif()
|
||||
#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)
|
||||
|
||||
# message("Using polyscope..")
|
||||
# target_include_directories(${PROJECT_NAME} PUBLIC ${POLYSCOPE_SOURCE_DIR}/include)
|
||||
# target_link_libraries(${PROJECT_NAME} PUBLIC polyscope)
|
||||
#endif()
|
||||
|
||||
##vcglib devel branch
|
||||
FetchContent_Declare(vcglib
|
||||
download_project(PROJ vcglib_devel
|
||||
GIT_REPOSITORY https://gitea-s2i2s.isti.cnr.it/manolas/vcglib.git
|
||||
GIT_TAG devel
|
||||
)
|
||||
FetchContent_MakeAvailable(vcglib)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${vcglib_SOURCE_DIR})
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${vcglib_SOURCE_DIR}/wrap/ply/plylib.cpp)
|
||||
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)
|
||||
|
||||
###matplot++ lib
|
||||
FetchContent_Declare(matplot
|
||||
##matplot++ lib
|
||||
set(MATPLOTPLUSPLUS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/matplot)
|
||||
download_project(PROJ MATPLOTPLUSPLUS
|
||||
GIT_REPOSITORY https://github.com/alandefreitas/matplotplusplus
|
||||
GIT_TAG master
|
||||
)
|
||||
FetchContent_MakeAvailable(matplot)
|
||||
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
|
||||
if(NOT TARGET ThreedBeamFEA)
|
||||
FetchContent_Declare(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
|
||||
GIT_REPOSITORY https://gitea-s2i2s.isti.cnr.it/manolas/threed-beam-fea.git
|
||||
GIT_TAG master
|
||||
)
|
||||
FetchContent_MakeAvailable(threed-beam-fea)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ThreedBeamFEA)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${threed-beam-fea_SOURCE_DIR})
|
||||
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})
|
||||
|
||||
#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)
|
||||
##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})
|
||||
###Eigen 3 NOTE: Eigen is required on the system the code is ran
|
||||
find_package(Eigen3 3.3 REQUIRED)
|
||||
if(MSVC)
|
||||
add_compile_definitions(_HAS_STD_BYTE=0)
|
||||
endif(MSVC)
|
||||
#link_directories(${CMAKE_CURRENT_LIST_DIR}/boost_graph/libs)
|
||||
|
||||
if(${MYSOURCES_STATIC_LINK})
|
||||
message("STATIC LINK MY SOURCES:" ${MYSOURCES_STATIC_LINK})
|
||||
endif()
|
||||
if(${MYSOURCES_STATIC_LINK})
|
||||
message("Linking statically here")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC #[[-static]] Eigen3::Eigen pthread gfortran quadmath matplot)
|
||||
message("Linking statically")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -static Eigen3::Eigen matplot ThreedBeamFEA ${TBB_BINARY_DIR}/libtbb_static.a #[[tbb_static]] pthread gfortran quadmath)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen tbb pthread matplot)
|
||||
# set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen matplot ThreedBeamFEA tbb pthread)
|
||||
if(${USE_POLYSCOPE})
|
||||
message("Using polyscope")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC polyscope)
|
||||
endif()
|
||||
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 ${threed-beam-fea_SOURCE_DIR}
|
||||
PUBLIC matplot
|
||||
)
|
||||
|
||||
|
||||
#if(USE_ENSMALLEN)
|
||||
set(ARMADILLO_SOURCE_DIR "/home/iason/Coding/Libraries/armadillo")
|
||||
set(ARMADILLO_BIN_DIR "/home/iason/Coding/Libraries/armadillo/build")
|
||||
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)
|
||||
#endif()
|
||||
#target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/build/FormFInder/Debug/_deps/armadillo-build/libarmadillo.a")
|
||||
|
||||
|
||||
if(${USE_ENSMALLEN})
|
||||
set(ENSMALLEN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/ensmallen)
|
||||
download_project(PROJ ENSMALLEN
|
||||
GIT_REPOSITORY https://github.com/mlpack/ensmallen.git
|
||||
GIT_TAG master
|
||||
BINARY_DIR ${ENSMALLEN_BINARY_DIR}
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC ${ENSMALLEN_SOURCE_DIR}/include)
|
||||
add_compile_definitions(USE_ENSMALLEN)
|
||||
###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)
|
||||
if(USE_ENSMALLEN)
|
||||
##ENSMALLEN
|
||||
set(ENSMALLEN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/ensmallen)
|
||||
download_project(PROJ ENSMALLEN
|
||||
GIT_REPOSITORY https://github.com/mlpack/ensmallen.git
|
||||
GIT_TAG master
|
||||
BINARY_DIR ${ENSMALLEN_BINARY_DIR}
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${ENSMALLEN_SOURCE_DIR} ${ENSMALLEN_BINARY_DIR})
|
||||
set(ARMADILLO_SOURCE_DIR "/home/iason/Coding/Libraries/armadillo")
|
||||
add_subdirectory(${ARMADILLO_SOURCE_DIR} ${EXTERNAL_DEPS_DIR}/armadillo_build)
|
||||
if(${MYSOURCES_STATIC_LINK})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC "-static" ensmallen ${EXTERNAL_DEPS_DIR}/armadillo_build/libarmadillo.a)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC armadillo ensmallen)
|
||||
endif()
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${ARMADILLO_SOURCE_DIR}/include ${ENSMALLEN_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
##Chrono
|
||||
##add_subdirectory("/home/iason/Coding/build/external dependencies/CHRONO-src" "/home/iason/Coding/build/external dependencies/CHRONO-src/build")
|
||||
##set(Chrono_DIR "/home/iason/Coding/Libraries/chrono-7.0.3/build/Release/cmake")
|
||||
#set(Chrono_DIR "/home/iason/Coding/Libraries/chrono-7.0.3/build/Release/cmake")
|
||||
##LIST(APPEND CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}/../Chrono/lib")
|
||||
#find_package(Chrono CONFIG
|
||||
# )
|
||||
#if (NOT Chrono_FOUND)
|
||||
# message("Could not find Chrono or one of its required modules")
|
||||
# return()
|
||||
#endif()
|
||||
#set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
# COMPILE_FLAGS "${CHRONO_CXX_FLAGS} ${EXTRA_COMPILE_FLAGS}"
|
||||
# COMPILE_DEFINITIONS "CHRONO_DATA_DIR=\"${CHRONO_DATA_DIR}\""
|
||||
# LINK_FLAGS "${CHRONO_LINKER_FLAGS}")
|
||||
#include_directories(${CHRONO_INCLUDE_DIRS})
|
||||
#target_link_libraries(${PROJECT_NAME} PUBLIC ${CHRONO_LIBRARIES})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/chrono-7.0.3/src" #[[${CHRONO_INCLUDE_DIRS}]] #[["/home/iason/Coding/Libraries/chrono-7.0.3/src"]] #[["/usr/include/irrlicht"]] )
|
||||
#target_link_directories(${PROJECT_NAME} PRIVATE "/home/iason/Coding/build/external dependencies/CHRONO-src/build/RelWithDebInfo/lib")
|
||||
#target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/build/external dependencies/CHRONO-src/build/RelWithDebInfo/lib/libChronoEngine.a")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/chrono-7.0.3/build/Release/lib/libChronoEngine.a")
|
||||
|
||||
|
||||
#add_subdirectory("/home/iason/Coding/Projects/Approximating shapes with flat patterns/Elastic rods/ElasticRods")
|
||||
#set(MESHFEM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/meshfem)
|
||||
#download_project(PROJ MESHFEM
|
||||
# GIT_REPOSITORY https://github.com/MeshFEM/MeshFEM.git
|
||||
# GIT_TAG 3847ffaeb6e9c4bbe15f0f81f5c773c7c481c059
|
||||
# BINARY_DIR ${MESHFEM_BINARY_DIR}
|
||||
# PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
# ${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
#)
|
||||
#add_subdirectory(${MESHFEM_SOURCE_DIR} ${MESHFEM_BINARY_DIR})
|
||||
#target_link_libraries(${PROJECT_NAME} PUBLIC MeshFEM)
|
||||
##target_include_directories(${PROJECT_NAME}
|
||||
##PUBLIC ${MESHFEM_SOURCE_DIR}/include)
|
||||
##add_compile_definitions(USE_ENSMALLEN)
|
||||
|
||||
##DER by panetta fork
|
||||
##set(FETCHCONTENT_SOURCE_DIR_LIBIGL "/home/iason/Coding/Libraries/libigl/cmake" CACHE PATH "not set")
|
||||
#set(LIBIGL_INCLUDE_DIR "/home/iason/Coding/Projects/Approximating shapes with flat patterns/Elastic rods/ElasticRods/3rdparty/libigl/include")
|
||||
##list(PREPEND CMAKE_MODULE_PATH "/home/iason/Coding/Libraries/libigl/cmake")
|
||||
##include(libigl)
|
||||
##add_subdirectory("/home/iason/Coding/Projects/Approximating shapes with flat patterns/Elastic rods/ElasticRods/3rdparty/MeshFEM/" ${EXTERNAL_DEPS_DIR}/MeshFEM)
|
||||
#set(DER_Panetta_dir "/home/iason/Coding/Projects/Approximating shapes with flat patterns/Elastic rods/DER_panneta_fork")
|
||||
#set(DER_Panetta_bin_dir "/home/iason/Coding/build/external dependencies/DER_panetta_fork")
|
||||
#add_subdirectory(${DER_Panetta_dir} ${DER_Panetta_bin_dir})
|
||||
##add_subdirectory("/home/iason/Coding/Projects/Approximating shapes with flat patterns/Elastic rods/ElasticRods/3rdparty/MeshFEM" "/home/iason/Coding/build/external dependencies/MeshFEM")
|
||||
##add_subdirectory("/home/iason/Coding/Projects/Approximating shapes with flat patterns/Elastic rods/ElasticRods/3rdparty/RotationOptimization" "/home/iason/Coding/build/external dependencies/RotationOptimization" )
|
||||
#target_link_directories(${PROJECT_NAME} PUBLIC "/home/iason/Coding/build/Elastic rods/DER_panneta_fork/Debug")
|
||||
#target_link_libraries(${PROJECT_NAME} PUBLIC RigidRodLinkages ElasticRods rotation_optimization MeshFEM "/home/iason/Coding/build/Elastic rods/DER_panneta_fork/Debug/3rdparty/visvalingam_simplify/src/libVisvalingamSimplify.a")
|
||||
#target_include_directories(${PROJECT_NAME} PUBLIC ${DER_Panetta_dir} )
|
||||
|
||||
##TBB
|
||||
if(NOT TARGET tbb_static AND NOT TARGET 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})
|
||||
message("Using tbb")
|
||||
FetchContent_Declare(tbb
|
||||
GIT_REPOSITORY https://github.com/wjakob/tbb.git
|
||||
GIT_TAG master
|
||||
)
|
||||
FetchContent_MakeAvailable(tbb)
|
||||
# target_link_libraries(${PROJECT_NAME} PRIVATE tbb_static)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE tbb_static)
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.14.2, 2021-07-15T10:27:01. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{4ab9621f-3cb4-4d5c-a5a5-8f7ea53a6f0f}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">false</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">6</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clang</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clang</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{08d5b07f-8010-48d8-a202-51411d8039c8}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="CMake.Initial.Parameters">-GUnix Makefiles
|
||||
-DCMAKE_BUILD_TYPE:String=Debug
|
||||
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
|
||||
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
|
||||
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/iason/Coding/Libraries/MySources_viscousDampingBranch/../build-MySources_viscousDampingBranch-Clang-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="QString" key="CMake.Initial.Parameters">-GUnix Makefiles
|
||||
-DCMAKE_BUILD_TYPE:String=Release
|
||||
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
|
||||
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
|
||||
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/iason/Coding/Libraries/MySources_viscousDampingBranch/../build-MySources_viscousDampingBranch-Clang-Release</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
||||
<value type="QString" key="CMake.Initial.Parameters">-GUnix Makefiles
|
||||
-DCMAKE_BUILD_TYPE:String=RelWithDebInfo
|
||||
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
|
||||
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
|
||||
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/iason/Coding/Libraries/MySources_viscousDampingBranch/../build-MySources_viscousDampingBranch-Clang-RelWithDebInfo</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
|
||||
<value type="QString" key="CMake.Initial.Parameters">-GUnix Makefiles
|
||||
-DCMAKE_BUILD_TYPE:String=MinSizeRel
|
||||
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
|
||||
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
|
||||
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/iason/Coding/Libraries/MySources_viscousDampingBranch/../build-MySources_viscousDampingBranch-Clang-MinSizeRel</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">4</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
||||
<value type="QString">cpu-cycles</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
|
||||
<value type="int" key="Analyzer.Perf.Frequency">250</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
|
||||
<value type="QString">-e</value>
|
||||
<value type="QString">cpu-cycles</value>
|
||||
<value type="QString">--call-graph</value>
|
||||
<value type="QString">dwarf,4096</value>
|
||||
<value type="QString">-F</value>
|
||||
<value type="QString">250</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
|
||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
|
@ -0,0 +1,80 @@
|
|||
#ifndef BEAM_HPP
|
||||
#define BEAM_HPP
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
struct RectangularBeamDimensions {
|
||||
inline static std::string name{"Rectangular"};
|
||||
double b;
|
||||
double h;
|
||||
|
||||
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;
|
||||
|
||||
RectangularBeamDimensions(const double &width, const double &height) : b(width), h(height)
|
||||
{
|
||||
assert(width > 0 && height > 0);
|
||||
updateProperties();
|
||||
}
|
||||
RectangularBeamDimensions() : b(0.002), h(0.002) { updateProperties(); }
|
||||
std::string toString() const {
|
||||
return std::string("b=") + std::to_string(b) + std::string(" h=") +
|
||||
std::to_string(h);
|
||||
}
|
||||
|
||||
void updateProperties()
|
||||
{
|
||||
A = b * h;
|
||||
inertia.I2 = b * std::pow(h, 3) / 12;
|
||||
inertia.I3 = h * std::pow(b, 3) / 12;
|
||||
inertia.J = inertia.I2 + inertia.I3;
|
||||
}
|
||||
static void computeMomentsOfInertia(const RectangularBeamDimensions &dimensions,
|
||||
MomentsOfInertia &inertia);
|
||||
};
|
||||
|
||||
struct CylindricalBeamDimensions {
|
||||
inline static std::string name{"Cylindrical"};
|
||||
double od; // Cylinder outside diameter
|
||||
double
|
||||
id; // Cylinder inside diameter
|
||||
// https://www.engineeringtoolbox.com/area-moment-inertia-d_1328.html
|
||||
CylindricalBeamDimensions(const double &outsideDiameter,
|
||||
const double &insideDiameter)
|
||||
: od(outsideDiameter), id(insideDiameter) {
|
||||
assert(outsideDiameter > 0 && insideDiameter > 0 &&
|
||||
outsideDiameter > insideDiameter);
|
||||
}
|
||||
CylindricalBeamDimensions() : od(0.03), id(0.026) {}
|
||||
};
|
||||
|
||||
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);
|
||||
updateProperties();
|
||||
}
|
||||
ElementMaterial() : poissonsRatio(0.3), youngsModulus(200 * 1e9) { updateProperties(); }
|
||||
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 updateProperties() { G = youngsModulus / (2 * (1 + poissonsRatio)); }
|
||||
};
|
||||
|
||||
#endif // BEAM_HPP
|
|
@ -1,13 +0,0 @@
|
|||
#include "chronoseulerlinearsimulationmodel.hpp"
|
||||
|
||||
ChronosEulerLinearSimulationModel::ChronosEulerLinearSimulationModel() {}
|
||||
|
||||
SimulationResults ChronosEulerLinearSimulationModel::executeSimulation(
|
||||
const std::shared_ptr<SimulationJob> &pJob) {
|
||||
ChronosEulerSimulationModel simulationModel;
|
||||
simulationModel.settings.analysisType =
|
||||
ChronosEulerSimulationModel::Settings::AnalysisType::Linear;
|
||||
auto simulationResults = simulationModel.executeSimulation(pJob);
|
||||
simulationResults.simulationModelUsed = label;
|
||||
return simulationResults;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef CHRONOSEULERLINEARSIMULATIONMODEL_HPP
|
||||
#define CHRONOSEULERLINEARSIMULATIONMODEL_HPP
|
||||
|
||||
#include "chronoseulersimulationmodel.hpp"
|
||||
|
||||
class ChronosEulerLinearSimulationModel : public ChronosEulerSimulationModel {
|
||||
public:
|
||||
ChronosEulerLinearSimulationModel();
|
||||
SimulationResults
|
||||
executeSimulation(const std::shared_ptr<SimulationJob> &pJob);
|
||||
inline static std::string label{"Linear_" +
|
||||
ChronosEulerSimulationModel::label};
|
||||
};
|
||||
|
||||
#endif // CHRONOSEULERLINEARSIMULATIONMODEL_HPP
|
|
@ -1,13 +0,0 @@
|
|||
#include "chronoseulernonlinearsimulationmodel.hpp"
|
||||
|
||||
ChronosEulerNonLinearSimulationModel::ChronosEulerNonLinearSimulationModel() {}
|
||||
|
||||
SimulationResults ChronosEulerNonLinearSimulationModel::executeSimulation(
|
||||
const std::shared_ptr<SimulationJob> &pJob) {
|
||||
ChronosEulerSimulationModel simulationModel;
|
||||
simulationModel.settings.analysisType =
|
||||
ChronosEulerSimulationModel::Settings::AnalysisType::NonLinear;
|
||||
auto simulationResults = simulationModel.executeSimulation(pJob);
|
||||
simulationResults.simulationModelUsed = label;
|
||||
return simulationResults;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef CHRONOSEULERNONLINEARSIMULATIONMODEL_HPP
|
||||
#define CHRONOSEULERNONLINEARSIMULATIONMODEL_HPP
|
||||
|
||||
#include "chronoseulersimulationmodel.hpp"
|
||||
|
||||
class ChronosEulerNonLinearSimulationModel
|
||||
: public ChronosEulerSimulationModel {
|
||||
public:
|
||||
ChronosEulerNonLinearSimulationModel();
|
||||
SimulationResults
|
||||
executeSimulation(const std::shared_ptr<SimulationJob> &pJob);
|
||||
inline static std::string label{"NonLinear_" +
|
||||
ChronosEulerSimulationModel::label};
|
||||
};
|
||||
|
||||
#endif // CHRONOSEULERNONLINEARSIMULATIONMODEL_HPP
|
|
@ -1,307 +0,0 @@
|
|||
#include "chronoseulersimulationmodel.hpp"
|
||||
#include <chrono/fea/ChBeamSectionEuler.h>
|
||||
#include <chrono/fea/ChBuilderBeam.h>
|
||||
#include <chrono/fea/ChLoadsBeam.h>
|
||||
#include <chrono/fea/ChMesh.h>
|
||||
#include <chrono/fea/ChNodeFEAxyzrot.h>
|
||||
#include <chrono/physics/ChBody.h>
|
||||
#include <chrono/physics/ChSystemSMC.h>
|
||||
#include <chrono/solver/ChIterativeSolverLS.h>
|
||||
#include "chrono/physics/ChLoadContainer.h"
|
||||
|
||||
#include <chrono/assets/ChVisualization.h>
|
||||
#include <chrono/fea/ChElementBeamEuler.h>
|
||||
#include <chrono/fea/ChVisualizationFEAmesh.h>
|
||||
|
||||
using namespace chrono;
|
||||
using namespace chrono::fea;
|
||||
std::shared_ptr<ChMesh> ChronosEulerSimulationModel::convertToChronosMesh_Euler(
|
||||
const std::shared_ptr<SimulationEdgeMesh>& pMesh,
|
||||
std::vector<std::shared_ptr<ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronosNodes) {
|
||||
auto mesh_chronos = chrono_types::make_shared<ChMesh>();
|
||||
edgeMeshVertsToChronosNodes.clear();
|
||||
edgeMeshVertsToChronosNodes.resize(pMesh->VN(), nullptr);
|
||||
|
||||
// add nodes
|
||||
for (int vi = 0; vi < pMesh->VN(); vi++) {
|
||||
const auto& vertex = pMesh->vert[vi];
|
||||
ChVector<> vertexPos(vertex.cP()[0], vertex.cP()[1], vertex.cP()[2]);
|
||||
edgeMeshVertsToChronosNodes[vi] =
|
||||
chrono_types::make_shared<ChNodeFEAxyzrot>(ChFrame<>(vertexPos));
|
||||
mesh_chronos->AddNode(edgeMeshVertsToChronosNodes[vi]);
|
||||
}
|
||||
// add elements
|
||||
ChBuilderBeamEuler builder;
|
||||
for (int ei = 0; ei < pMesh->EN(); ei++) {
|
||||
const SimulationEdgeMesh::EdgeType& edge = pMesh->edge[ei];
|
||||
// define end-points
|
||||
const auto vi0 = pMesh->getIndex(edge.cV(0));
|
||||
const auto vi1 = pMesh->getIndex(edge.cV(1));
|
||||
// define cross section
|
||||
const Element& element = pMesh->elements[ei];
|
||||
const double beam_wz = element.dimensions.getDim1();
|
||||
const double beam_wy = element.dimensions.getDim2();
|
||||
const double E = element.material.youngsModulus;
|
||||
// const double poisson = element.material.poissonsRatio;
|
||||
const double density = 1e0;
|
||||
|
||||
// auto msection =
|
||||
// chrono_types::make_shared<ChBeamSectionEulerAdvanced>();
|
||||
auto msection =
|
||||
chrono_types::make_shared<ChBeamSectionEulerEasyRectangular>(
|
||||
beam_wy, beam_wz, E, element.material.G, density);
|
||||
msection->SetArea(element.dimensions.A);
|
||||
msection->SetIyy(element.dimensions.inertia.I2);
|
||||
msection->SetIzz(element.dimensions.inertia.I3);
|
||||
msection->SetJ(element.dimensions.inertia.J);
|
||||
// msection->SetDensity(density);
|
||||
// msection->SetYoungModulus(E);
|
||||
// msection->SetGwithPoissonRatio(poisson);
|
||||
// // msection->SetBeamRaleyghDamping(0.0);
|
||||
// msection->SetAsRectangularSection(beam_wy, beam_wz);
|
||||
builder.BuildBeam(
|
||||
mesh_chronos, // the mesh where to put the created nodes and elements
|
||||
msection, // the ChBeamSectionEuler to use for the ChElementBeamEuler
|
||||
// elements
|
||||
1, // the number of ChElementBeamEuler to create
|
||||
edgeMeshVertsToChronosNodes[vi0], // the 'A' point in space (beginning
|
||||
// of beam)
|
||||
edgeMeshVertsToChronosNodes[vi1], // the 'B' point in space (end of
|
||||
// beam)
|
||||
ChVector<>(0, 0, 1)
|
||||
// ChVector<>(0, cos(rot_rad), sin(rot_rad))
|
||||
); // the 'Y' up direction of the section for the beam
|
||||
}
|
||||
|
||||
return mesh_chronos;
|
||||
}
|
||||
|
||||
ChronosEulerSimulationModel::ChronosEulerSimulationModel() {}
|
||||
|
||||
// SimulationResults ChronosEulerSimulationModel::executeSimulation(
|
||||
// const std::shared_ptr<SimulationJob> &pJob)
|
||||
//{}
|
||||
|
||||
// chrono::ChSystemSMC convertToChronosSystem(const
|
||||
// std::shared_ptr<SimulationJob> &pJob)
|
||||
//{
|
||||
// chrono::ChSystemSMC my_system;
|
||||
//}
|
||||
|
||||
void ChronosEulerSimulationModel::parseForces(
|
||||
const std::shared_ptr<chrono::fea::ChMesh>& mesh_chronos,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronoNodes,
|
||||
const std::unordered_map<VertexIndex, Vector6d>& nodalExternalForces) {
|
||||
mesh_chronos->SetAutomaticGravity(false);
|
||||
for (const std::pair<VertexIndex, Vector6d>& externalForce :
|
||||
nodalExternalForces) {
|
||||
const int& forceVi = externalForce.first;
|
||||
const Vector6d& force = externalForce.second;
|
||||
edgeMeshVertsToChronoNodes[forceVi]->SetForce(
|
||||
ChVector<>(force[0], force[1], force[2]));
|
||||
edgeMeshVertsToChronoNodes[forceVi]->SetTorque(
|
||||
ChVector<>(force[3], force[4], force[5]));
|
||||
}
|
||||
}
|
||||
|
||||
void ChronosEulerSimulationModel::parseForcedDisplacements(
|
||||
const std::shared_ptr<const SimulationJob>& pJob,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronoNodes,
|
||||
chrono::ChSystemSMC& my_system) {
|
||||
assert(!edgeMeshVertsToChronoNodes.empty());
|
||||
|
||||
ChState x;
|
||||
ChStateDelta v;
|
||||
double t;
|
||||
for (const std::pair<VertexIndex, Eigen::Vector3d>& forcedDisplacement :
|
||||
pJob->nodalForcedDisplacements) {
|
||||
assert(false);
|
||||
std::cerr << "Forced displacements dont work" << std::endl;
|
||||
// std::terminate();
|
||||
const int& constrainedVi = forcedDisplacement.first;
|
||||
ChVector<double> displacementVector(
|
||||
pJob->nodalForcedDisplacements.at(constrainedVi));
|
||||
const std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>& constrainedChronoNode =
|
||||
edgeMeshVertsToChronoNodes[constrainedVi];
|
||||
constrainedChronoNode->NodeIntStateGather(0, x, 0, v, t);
|
||||
std::cout << "state rows:" << x.rows() << std::endl;
|
||||
std::cout << "state cols:" << x.cols() << std::endl;
|
||||
// x = x + displacementVector;
|
||||
constrainedChronoNode->NodeIntStateScatter(0, x, 0, v, t);
|
||||
}
|
||||
}
|
||||
void ChronosEulerSimulationModel::parseConstrainedVertices(
|
||||
const std::shared_ptr<const SimulationJob>& pJob,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronoNodes,
|
||||
chrono::ChSystemSMC& my_system) {
|
||||
assert(!edgeMeshVertsToChronoNodes.empty());
|
||||
for (const std::pair<VertexIndex, std::unordered_set<int>>&
|
||||
constrainedVertex : pJob->constrainedVertices) {
|
||||
const int& constrainedVi = constrainedVertex.first;
|
||||
const std::unordered_set<int>& constrainedDoF = constrainedVertex.second;
|
||||
// Create a truss
|
||||
auto truss = chrono_types::make_shared<ChBody>();
|
||||
truss->SetBodyFixed(true);
|
||||
my_system.Add(truss);
|
||||
const std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>& constrainedChronoNode =
|
||||
edgeMeshVertsToChronoNodes[constrainedVi];
|
||||
auto constraint = chrono_types::make_shared<ChLinkMateGeneric>();
|
||||
constraint->SetConstrainedCoords(
|
||||
constrainedDoF.contains(0), constrainedDoF.contains(1),
|
||||
constrainedDoF.contains(2), constrainedDoF.contains(3),
|
||||
constrainedDoF.contains(4), constrainedDoF.contains(5));
|
||||
constraint->Initialize(constrainedChronoNode, truss, false,
|
||||
constrainedChronoNode->Frame(),
|
||||
constrainedChronoNode->Frame());
|
||||
my_system.Add(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
SimulationResults ChronosEulerSimulationModel::executeSimulation(
|
||||
const std::shared_ptr<SimulationJob>& pJob) {
|
||||
assert(pJob->pMesh->VN() != 0);
|
||||
// const bool structureInitialized = mesh_chronos != nullptr;
|
||||
// const bool wasInitializedWithDifferentStructure =
|
||||
// structureInitialized &&
|
||||
// (pJob->pMesh->EN() != mesh_chronos->GetNelements() ||
|
||||
// pJob->pMesh->VN() != mesh_chronos->GetNnodes());
|
||||
// if (!structureInitialized || wasInitializedWithDifferentStructure) {
|
||||
setStructure(pJob->pMesh);
|
||||
// }
|
||||
chrono::ChSystemSMC my_system;
|
||||
// chrono::irrlicht::ChIrrApp application(&my_system,
|
||||
// L"Irrlicht FEM visualization",
|
||||
// irr::core::dimension2d<irr::u32>(800,
|
||||
// 600),
|
||||
// chrono::irrlicht::VerticalDir::Z,
|
||||
// false,
|
||||
// true);
|
||||
// const std::string chronoDataFolderPath =
|
||||
// "/home/iason/Coding/build/external "
|
||||
// "dependencies/CHRONO-src/data/";
|
||||
// application.AddTypicalLogo(chronoDataFolderPath +
|
||||
// "logo_chronoengine_alpha.png");
|
||||
// application.AddTypicalSky(chronoDataFolderPath + "skybox/");
|
||||
// application.AddTypicalLights();
|
||||
// application.AddTypicalCamera(irr::core::vector3df(0, (irr::f32) 0.6,
|
||||
// -1));
|
||||
// my_system.SetTimestepperType(chrono::ChTimestepper::Type::EULER_IMPLICIT_LINEARIZED);
|
||||
// parse forces
|
||||
parseForcedDisplacements(pJob, edgeMeshVertsToChronoNodes, my_system);
|
||||
parseForces(mesh_chronos, edgeMeshVertsToChronoNodes,
|
||||
pJob->nodalExternalForces);
|
||||
// parse constrained vertices
|
||||
parseConstrainedVertices(pJob, edgeMeshVertsToChronoNodes, my_system);
|
||||
// std::dynamic_pointer_cast<std::shared_ptr<ChNodeFEAxyzrot>>(mesh_chronos->GetNode(1))
|
||||
// ->SetFixed(true);
|
||||
// and load containers must be added to your system
|
||||
// auto mvisualizemesh =
|
||||
// chrono_types::make_shared<ChVisualizationFEAmesh>(*(mesh_chronos.get()));
|
||||
// mvisualizemesh->SetFEMdataType(ChVisualizationFEAmesh::E_PLOT_NODE_DISP_NORM);
|
||||
// mvisualizemesh->SetColorscaleMinMax(0.0, 5.50);
|
||||
// mvisualizemesh->SetShrinkElements(false, 0.85);
|
||||
// mvisualizemesh->SetSmoothFaces(false);
|
||||
// mesh_chronos->AddAsset(mvisualizemesh);
|
||||
|
||||
// application.AssetBindAll();
|
||||
// application.AssetUpdateAll();
|
||||
my_system.Add(mesh_chronos);
|
||||
|
||||
auto solver = chrono_types::make_shared<ChSolverMINRES>();
|
||||
my_system.SetSolver(solver);
|
||||
solver->SetMaxIterations(1e5);
|
||||
solver->EnableWarmStart(
|
||||
true); // IMPORTANT for convergence when using EULER_IMPLICIT_LINEARIZED
|
||||
solver->EnableDiagonalPreconditioner(true);
|
||||
// solver->SetTolerance(1e-15);
|
||||
my_system.SetSolverForceTolerance(1e-15);
|
||||
|
||||
SimulationResults simulationResults;
|
||||
//#ifdef POLYSCOPE_DEFINED
|
||||
// solver->SetVerbose(true);
|
||||
// // edgeMeshVertsToChronoNodes[10]->Frame().Move({0, 0, 1e-1});
|
||||
// simulationResults.converged = my_system.DoEntireKinematics(5e2);
|
||||
//// edgeMeshVertsToChronoNodes[10]->SetForce({0, 0, 1e6});
|
||||
//#else
|
||||
solver->SetVerbose(false);
|
||||
if (settings.analysisType == Settings::AnalysisType::Linear) {
|
||||
simulationResults.converged = my_system.DoStaticLinear();
|
||||
// simulationResults.converged = my_system.DoStaticRelaxing();
|
||||
} else {
|
||||
simulationResults.converged = my_system.DoStaticNonlinear();
|
||||
// simulationResults.converged = my_system.DoStaticRelaxing();
|
||||
}
|
||||
//#endif
|
||||
if (!simulationResults.converged) {
|
||||
std::cerr << "Simulation failed" << std::endl;
|
||||
assert(false);
|
||||
return simulationResults;
|
||||
}
|
||||
|
||||
// my_system.SetTimestepperType(ChTimestepper::Type::EULER_IMPLICIT_LINEARIZED);
|
||||
// application.SetTimestep(0.001);
|
||||
|
||||
// while (application.GetDevice()->run()) {
|
||||
// application.BeginScene();
|
||||
// application.DrawAll();
|
||||
// application.EndScene();
|
||||
// }
|
||||
simulationResults.pJob = pJob;
|
||||
simulationResults.displacements.resize(pJob->pMesh->VN());
|
||||
simulationResults.rotationalDisplacementQuaternion.resize(pJob->pMesh->VN());
|
||||
for (size_t vi = 0; vi < pJob->pMesh->VN(); vi++) {
|
||||
const auto node_chronos = edgeMeshVertsToChronoNodes[vi];
|
||||
const auto posDisplacement =
|
||||
node_chronos->Frame().GetPos() - node_chronos->GetX0().GetPos();
|
||||
// std::cout << "Node " << vi << " coordinate x= " <<
|
||||
// node_chronos->Frame().GetPos().x()
|
||||
// << " y=" << node_chronos->Frame().GetPos().y()
|
||||
// << " z=" << node_chronos->Frame().GetPos().z() <<
|
||||
// "\n";
|
||||
// Translations
|
||||
simulationResults.displacements[vi][0] = posDisplacement[0];
|
||||
simulationResults.displacements[vi][1] = posDisplacement[1];
|
||||
simulationResults.displacements[vi][2] = posDisplacement[2];
|
||||
// Rotations
|
||||
chrono::ChQuaternion<double> rotQuat = node_chronos->GetRot();
|
||||
simulationResults.rotationalDisplacementQuaternion[vi] =
|
||||
Eigen::Quaternion<double>(rotQuat.e0(), rotQuat.e1(), rotQuat.e2(),
|
||||
rotQuat.e3());
|
||||
const Eigen::Vector3d eulerAngles =
|
||||
simulationResults.rotationalDisplacementQuaternion[vi]
|
||||
.toRotationMatrix()
|
||||
.eulerAngles(0, 1, 2);
|
||||
// std::cout << "Euler angles:" << eulerAngles << std::endl;
|
||||
simulationResults.displacements[vi][3] = eulerAngles[0];
|
||||
simulationResults.displacements[vi][4] = eulerAngles[1];
|
||||
simulationResults.displacements[vi][5] = eulerAngles[2];
|
||||
}
|
||||
|
||||
simulationResults.simulationModelUsed = label;
|
||||
return simulationResults;
|
||||
|
||||
// VCGEdgeMesh deformedMesh;
|
||||
// deformedMesh.copy(*(pJob->pMesh));
|
||||
// for (size_t vi = 0; vi < pJob->pMesh->VN(); vi++) {
|
||||
// const std::shared_ptr<ChNodeFEAxyzrot> node_chronos =
|
||||
// edgeMeshVertsToChronosNodes[vi]; deformedMesh.vert[vi].P() =
|
||||
// CoordType(node_chronos->GetPos()[0],
|
||||
// node_chronos->GetPos()[1],
|
||||
// node_chronos->GetPos()[2]);
|
||||
// }
|
||||
|
||||
// deformedMesh.updateEigenEdgeAndVertices();
|
||||
// deformedMesh.setLabel("deformed");
|
||||
// deformedMesh.registerForDrawing();
|
||||
// polyscope::show();
|
||||
// return simulationResults;
|
||||
}
|
||||
|
||||
void ChronosEulerSimulationModel::setStructure(
|
||||
const std::shared_ptr<SimulationEdgeMesh>& pMesh) {
|
||||
mesh_chronos = convertToChronosMesh_Euler(pMesh, edgeMeshVertsToChronoNodes);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
#ifndef CHRONOSEULERSIMULATIONMODEL_HPP
|
||||
#define CHRONOSEULERSIMULATIONMODEL_HPP
|
||||
|
||||
#include "simulationmodel.hpp"
|
||||
|
||||
namespace chrono {
|
||||
class ChSystemSMC;
|
||||
namespace fea {
|
||||
class ChMesh;
|
||||
class ChNodeFEAxyzrot;
|
||||
} // namespace fea
|
||||
} // namespace chrono
|
||||
|
||||
class ChronosEulerSimulationModel : public SimulationModel {
|
||||
std::shared_ptr<chrono::fea::ChMesh> mesh_chronos;
|
||||
std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>
|
||||
edgeMeshVertsToChronoNodes;
|
||||
|
||||
static void parseConstrainedVertices(
|
||||
const std::shared_ptr<const SimulationJob>& pJob,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronoNodes,
|
||||
chrono::ChSystemSMC& my_system);
|
||||
static void parseForces(
|
||||
const std::shared_ptr<chrono::fea::ChMesh>& mesh_chronos,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronoNodes,
|
||||
const std::unordered_map<VertexIndex, Vector6d>& nodalExternalForces);
|
||||
|
||||
static void parseForcedDisplacements(
|
||||
const std::shared_ptr<const SimulationJob>& pJob,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronoNodes,
|
||||
chrono::ChSystemSMC& my_system);
|
||||
|
||||
public:
|
||||
ChronosEulerSimulationModel();
|
||||
SimulationResults executeSimulation(
|
||||
const std::shared_ptr<SimulationJob>& pJob) override;
|
||||
void setStructure(const std::shared_ptr<SimulationEdgeMesh>& pMesh) override;
|
||||
static std::shared_ptr<chrono::fea::ChMesh> convertToChronosMesh_Euler(
|
||||
const std::shared_ptr<SimulationEdgeMesh>& pMesh,
|
||||
std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>>&
|
||||
edgeMeshVertsToChronosNodes);
|
||||
|
||||
inline const static std::string label{"Chronos_Euler"};
|
||||
|
||||
struct Settings {
|
||||
enum AnalysisType { Linear = 0, NonLinear };
|
||||
AnalysisType analysisType{NonLinear};
|
||||
};
|
||||
Settings settings;
|
||||
};
|
||||
|
||||
#endif // CHRONOSEULERSIMULATIONMODEL_HPP
|
|
@ -1,300 +0,0 @@
|
|||
#include "chronosigasimulationmodel.hpp"
|
||||
#include "chrono/physics/ChLoadContainer.h"
|
||||
#include <chrono/fea/ChBeamSectionEuler.h>
|
||||
#include <chrono/fea/ChBuilderBeam.h>
|
||||
#include <chrono/fea/ChLoadsBeam.h>
|
||||
#include <chrono/fea/ChMesh.h>
|
||||
#include <chrono/fea/ChNodeFEAxyzrot.h>
|
||||
#include <chrono/physics/ChBody.h>
|
||||
#include <chrono/physics/ChSystemSMC.h>
|
||||
#include <chrono/solver/ChIterativeSolverLS.h>
|
||||
|
||||
#include <chrono/assets/ChVisualization.h>
|
||||
#include <chrono/fea/ChElementBeamEuler.h>
|
||||
#include <chrono/fea/ChVisualizationFEAmesh.h>
|
||||
|
||||
using namespace chrono;
|
||||
using namespace chrono::fea;
|
||||
std::shared_ptr<ChMesh> ChronosIGASimulationModel::convertToChronosMesh_IGA(
|
||||
const std::shared_ptr<SimulationEdgeMesh> &pMesh,
|
||||
std::vector<std::shared_ptr<ChNodeFEAxyzrot>> &edgeMeshVertsToChronosNodes)
|
||||
{
|
||||
auto mesh_chronos = chrono_types::make_shared<ChMesh>();
|
||||
edgeMeshVertsToChronosNodes.clear();
|
||||
edgeMeshVertsToChronosNodes.resize(pMesh->VN(), nullptr);
|
||||
|
||||
//add nodes
|
||||
for (int vi = 0; vi < pMesh->VN(); vi++) {
|
||||
const auto &vertex = pMesh->vert[vi];
|
||||
ChVector<> vertexPos(vertex.cP()[0], vertex.cP()[1], vertex.cP()[2]);
|
||||
edgeMeshVertsToChronosNodes[vi] = chrono_types::make_shared<ChNodeFEAxyzrot>(
|
||||
ChFrame<>(vertexPos));
|
||||
mesh_chronos->AddNode(edgeMeshVertsToChronosNodes[vi]);
|
||||
}
|
||||
//add elements
|
||||
ChBuilderBeamIGA builder;
|
||||
for (int ei = 0; ei < pMesh->EN(); ei++) {
|
||||
const SimulationEdgeMesh::EdgeType &edge = pMesh->edge[ei];
|
||||
//define end-points
|
||||
const auto vi0 = pMesh->getIndex(edge.cV(0));
|
||||
const auto vi1 = pMesh->getIndex(edge.cV(1));
|
||||
//define cross section
|
||||
const Element &element = pMesh->elements[ei];
|
||||
const double beam_wz = element.dimensions.getDim1();
|
||||
const double beam_wy = element.dimensions.getDim2();
|
||||
const double E = element.material.youngsModulus;
|
||||
// const double poisson = element.material.poissonsRatio;
|
||||
const double density = 1e0;
|
||||
|
||||
// auto msection = chrono_types::make_shared<ChBeamSectionEulerAdvanced>();
|
||||
auto msection = chrono_types::make_shared<ChBeamSectionCosseratEasyRectangular>(
|
||||
beam_wy, beam_wz, E, element.material.G, density);
|
||||
// msection->SetDensity(density);
|
||||
// msection->SetYoungModulus(E);
|
||||
// msection->SetGwithPoissonRatio(poisson);
|
||||
// // msection->SetBeamRaleyghDamping(0.0);
|
||||
// msection->SetAsRectangularSection(beam_wy, beam_wz);
|
||||
builder
|
||||
.BuildBeam(mesh_chronos, // the mesh where to put the created nodes and elements
|
||||
msection, // the ChBeamSectionEuler to use for the ChElementBeamEuler elements
|
||||
1, // the number of ChElementBeamEuler to create
|
||||
edgeMeshVertsToChronosNodes[vi0], // the 'A' point in space (beginning of beam)
|
||||
edgeMeshVertsToChronosNodes[vi1], // the 'B' point in space (end of beam)
|
||||
ChVector<>(0, 0, 1),
|
||||
3
|
||||
// ChVector<>(0, cos(rot_rad), sin(rot_rad))
|
||||
); // the 'Y' up direction of the section for the beam
|
||||
const auto lastBeamNodesVector = builder.GetLastBeamNodes();
|
||||
// assert(lastBeamNodesVector.size() == 4);
|
||||
edgeMeshVertsToChronosNodes[vi0] = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(
|
||||
mesh_chronos->GetNode(mesh_chronos->GetNnodes() - lastBeamNodesVector.size()));
|
||||
edgeMeshVertsToChronosNodes[vi1] = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(
|
||||
mesh_chronos->GetNode(mesh_chronos->GetNnodes() - 1));
|
||||
// std::cout << edgeMeshVertsToChronosNodes[vi1]->GetCoord().pos[0] << " "
|
||||
// << edgeMeshVertsToChronosNodes[vi1]->GetCoord().pos[1] << " "
|
||||
// << edgeMeshVertsToChronosNodes[vi1]->GetCoord().pos[2] << std::endl;
|
||||
// std::cout << lastBeamNodesVector.back()->GetCoord().pos[0] << " "
|
||||
// << lastBeamNodesVector.back()->GetCoord().pos[1] << " "
|
||||
// << lastBeamNodesVector.back()->GetCoord().pos[2] << std::endl;
|
||||
// int i = 0;
|
||||
// i++;
|
||||
}
|
||||
|
||||
return mesh_chronos;
|
||||
}
|
||||
|
||||
//SimulationResults ChronosEulerSimulationModel::executeSimulation(
|
||||
// const std::shared_ptr<SimulationJob> &pJob)
|
||||
//{}
|
||||
|
||||
//chrono::ChSystemSMC convertToChronosSystem(const std::shared_ptr<SimulationJob> &pJob)
|
||||
//{
|
||||
// chrono::ChSystemSMC my_system;
|
||||
//}
|
||||
|
||||
void ChronosIGASimulationModel::parseForces(
|
||||
const std::shared_ptr<chrono::fea::ChMesh> &mesh_chronos,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>> &edgeMeshVertsToChronoNodes,
|
||||
const std::unordered_map<VertexIndex, Vector6d> &nodalExternalForces)
|
||||
{
|
||||
mesh_chronos->SetAutomaticGravity(false);
|
||||
for (const std::pair<VertexIndex, Vector6d> &externalForce : nodalExternalForces) {
|
||||
const int &forceVi = externalForce.first;
|
||||
const Vector6d &force = externalForce.second;
|
||||
edgeMeshVertsToChronoNodes[forceVi]->SetForce(ChVector<>(force[0], force[1], force[2]));
|
||||
edgeMeshVertsToChronoNodes[forceVi]->SetTorque(ChVector<>(force[3], force[4], force[5]));
|
||||
std::cout << "Force on vertex:" << std::endl;
|
||||
std::cout << edgeMeshVertsToChronoNodes[forceVi]->GetCoord().pos[0] << " "
|
||||
<< edgeMeshVertsToChronoNodes[forceVi]->GetCoord().pos[1] << " "
|
||||
<< edgeMeshVertsToChronoNodes[forceVi]->GetCoord().pos[2] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ChronosIGASimulationModel::parseConstrainedVertices(
|
||||
const std::shared_ptr<const SimulationJob> &pJob,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>> &edgeMeshVertsToChronoNodes,
|
||||
chrono::ChSystemSMC &my_system)
|
||||
{
|
||||
assert(!edgeMeshVertsToChronoNodes.empty());
|
||||
for (const std::pair<VertexIndex, std::unordered_set<int>> &constrainedVertex :
|
||||
pJob->constrainedVertices) {
|
||||
const int &constrainedVi = constrainedVertex.first;
|
||||
const std::unordered_set<int> &constrainedDoF = constrainedVertex.second;
|
||||
// Create a truss
|
||||
auto truss = chrono_types::make_shared<ChBody>();
|
||||
truss->SetBodyFixed(true);
|
||||
my_system.Add(truss);
|
||||
const auto &constrainedChronoNode = edgeMeshVertsToChronoNodes[constrainedVi];
|
||||
std::cout << "Constrained vertex:" << std::endl;
|
||||
std::cout << edgeMeshVertsToChronoNodes[constrainedVi]->GetCoord().pos[0] << " "
|
||||
<< edgeMeshVertsToChronoNodes[constrainedVi]->GetCoord().pos[1] << " "
|
||||
<< edgeMeshVertsToChronoNodes[constrainedVi]->GetCoord().pos[2] << std::endl;
|
||||
// Create a constraint at the end of the beam
|
||||
auto constr_a = chrono_types::make_shared<ChLinkMateGeneric>();
|
||||
constr_a->SetConstrainedCoords(constrainedDoF.contains(0),
|
||||
constrainedDoF.contains(1),
|
||||
constrainedDoF.contains(2),
|
||||
constrainedDoF.contains(3),
|
||||
constrainedDoF.contains(4),
|
||||
constrainedDoF.contains(5));
|
||||
constr_a->Initialize(constrainedChronoNode,
|
||||
truss,
|
||||
false,
|
||||
constrainedChronoNode->Frame(),
|
||||
constrainedChronoNode->Frame());
|
||||
// const auto frameNode = constrainedChronoNode->Frame();
|
||||
my_system.Add(constr_a);
|
||||
|
||||
// edgeMeshVertsToChronoNodes[constrainedVi]->SetFixed(true);
|
||||
// if (vertexIsFullyConstrained) {
|
||||
// } else {
|
||||
// std::cerr << "Currently only rigid vertices are handled." << std::endl;
|
||||
// // SimulationResults simulationResults;
|
||||
// // simulationResults.converged = false;
|
||||
// // assert(false);
|
||||
// // return simulationResults;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
SimulationResults ChronosIGASimulationModel::executeSimulation(
|
||||
const std::shared_ptr<SimulationJob> &pJob)
|
||||
{
|
||||
// assert(pJob->pMesh->VN() != 0);
|
||||
// const bool structureInitialized = mesh_chronos != nullptr;
|
||||
// const bool wasInitializedWithDifferentStructure = structureInitialized
|
||||
// && (pJob->pMesh->EN()
|
||||
// != mesh_chronos->GetNelements()
|
||||
// || pJob->pMesh->VN()
|
||||
// != mesh_chronos->GetNnodes());
|
||||
chrono::ChSystemSMC my_system;
|
||||
// if (!structureInitialized || wasInitializedWithDifferentStructure) {
|
||||
setStructure(pJob->pMesh);
|
||||
my_system.Add(mesh_chronos);
|
||||
// }
|
||||
// chrono::irrlicht::ChIrrApp application(&my_system,
|
||||
// L"Irrlicht FEM visualization",
|
||||
// irr::core::dimension2d<irr::u32>(800, 600),
|
||||
// chrono::irrlicht::VerticalDir::Z,
|
||||
// false,
|
||||
// true);
|
||||
// const std::string chronoDataFolderPath = "/home/iason/Coding/build/external "
|
||||
// "dependencies/CHRONO-src/data/";
|
||||
// application.AddTypicalLogo(chronoDataFolderPath + "logo_chronoengine_alpha.png");
|
||||
// application.AddTypicalSky(chronoDataFolderPath + "skybox/");
|
||||
// application.AddTypicalLights();
|
||||
// application.AddTypicalCamera(irr::core::vector3df(0, (irr::f32) 0.6, -1));
|
||||
// my_system.SetTimestepperType(chrono::ChTimestepper::Type::EULER_IMPLICIT_LINEARIZED);
|
||||
const auto node_0 = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(mesh_chronos->GetNode(0));
|
||||
//parse forces
|
||||
// std::cout << node_0->GetCoord().pos[0] << " " << node_0->GetCoord().pos[1] << " "
|
||||
// << node_0->GetCoord().pos[2] << std::endl;
|
||||
parseForces(mesh_chronos, edgeMeshVertsToChronoNodes, pJob->nodalExternalForces);
|
||||
// std::cout << node_0->GetCoord().pos[0] << " " << node_0->GetCoord().pos[1] << " "
|
||||
// << node_0->GetCoord().pos[2] << std::endl;
|
||||
|
||||
//parse constrained vertices
|
||||
// std::cout << node_0->GetCoord().pos[0] << " " << node_0->GetCoord().pos[1] << " "
|
||||
// << node_0->GetCoord().pos[2] << std::endl;
|
||||
// parseConstrainedVertices(pJob, edgeMeshVertsToChronoNodes, my_system);
|
||||
|
||||
// std::cout << node_0->GetCoord().pos[0] << " " << node_0->GetCoord().pos[1] << " "
|
||||
// << node_0->GetCoord().pos[2] << std::endl;
|
||||
// std::dynamic_pointer_cast<std::shared_ptr<ChNodeFEAxyzrot>>(mesh_chronos->GetNode(1))
|
||||
// ->SetFixed(true);
|
||||
// and load containers must be added to your system
|
||||
// auto mvisualizemesh = chrono_types::make_shared<ChVisualizationFEAmesh>(*(mesh_chronos.get()));
|
||||
// mvisualizemesh->SetFEMdataType(ChVisualizationFEAmesh::E_PLOT_NODE_DISP_NORM);
|
||||
// mvisualizemesh->SetColorscaleMinMax(0.0, 5.50);
|
||||
// mvisualizemesh->SetShrinkElements(false, 0.85);
|
||||
// mvisualizemesh->SetSmoothFaces(false);
|
||||
// mesh_chronos->AddAsset(mvisualizemesh);
|
||||
|
||||
// application.AssetBindAll();
|
||||
// application.AssetUpdateAll();
|
||||
|
||||
auto solver = chrono_types::make_shared<ChSolverMINRES>();
|
||||
my_system.SetSolver(solver);
|
||||
solver->SetMaxIterations(1e5);
|
||||
// solver->SetTolerance(1e-12);
|
||||
solver->EnableWarmStart(true); // IMPORTANT for convergence when using EULER_IMPLICIT_LINEARIZED
|
||||
solver->EnableDiagonalPreconditioner(true);
|
||||
// my_system.SetSolverForceTolerance(1e-9);
|
||||
solver->SetVerbose(true);
|
||||
|
||||
std::cout << node_0->GetCoord().pos[0] << " " << node_0->GetCoord().pos[1] << " "
|
||||
<< node_0->GetCoord().pos[2] << std::endl;
|
||||
SimulationResults simulationResults;
|
||||
simulationResults.converged = my_system.DoStaticNonlinear();
|
||||
// simulationResults.converged = my_system.DoStaticLinear();
|
||||
std::cout << node_0->GetCoord().pos[0] << " " << node_0->GetCoord().pos[1] << " "
|
||||
<< node_0->GetCoord().pos[2] << std::endl;
|
||||
if (!simulationResults.converged) {
|
||||
std::cerr << "Simulation failed" << std::endl;
|
||||
assert(false);
|
||||
return simulationResults;
|
||||
}
|
||||
|
||||
// my_system.SetTimestepperType(ChTimestepper::Type::EULER_IMPLICIT_LINEARIZED);
|
||||
// application.SetTimestep(0.001);
|
||||
|
||||
// while (application.GetDevice()->run()) {
|
||||
// application.BeginScene();
|
||||
// application.DrawAll();
|
||||
// application.EndScene();
|
||||
// }
|
||||
simulationResults.pJob = pJob;
|
||||
simulationResults.displacements.resize(pJob->pMesh->VN());
|
||||
simulationResults.rotationalDisplacementQuaternion.resize(pJob->pMesh->VN());
|
||||
for (size_t vi = 0; vi < pJob->pMesh->VN(); vi++) {
|
||||
const auto node_chronos = edgeMeshVertsToChronoNodes[vi];
|
||||
std::cout << node_chronos->GetCoord().pos[0] << " " << node_chronos->GetCoord().pos[1]
|
||||
<< " " << node_chronos->GetCoord().pos[2] << std::endl;
|
||||
int i = 0;
|
||||
i++;
|
||||
assert(node_chronos != nullptr);
|
||||
const auto posDisplacement = node_chronos->Frame().GetPos()
|
||||
- node_chronos->GetX0().GetPos();
|
||||
// std::cout << "Node " << vi << " coordinate x= " << node_chronos->Frame().GetPos().x()
|
||||
// << " y=" << node_chronos->Frame().GetPos().y()
|
||||
// << " z=" << node_chronos->Frame().GetPos().z() << "\n";
|
||||
//Translations
|
||||
simulationResults.displacements[vi][0] = posDisplacement[0];
|
||||
simulationResults.displacements[vi][1] = posDisplacement[1];
|
||||
simulationResults.displacements[vi][2] = posDisplacement[2];
|
||||
//Rotations
|
||||
chrono::ChQuaternion<double> rotQuat = node_chronos->GetRot();
|
||||
simulationResults.rotationalDisplacementQuaternion[vi]
|
||||
= Eigen::Quaternion<double>(rotQuat.e0(), rotQuat.e1(), rotQuat.e2(), rotQuat.e3());
|
||||
const ChVector<double> eulerAngles = rotQuat.Q_to_Euler123();
|
||||
// std::cout << "Euler angles:" << eulerAngles << std::endl;
|
||||
simulationResults.displacements[vi][3] = eulerAngles[0];
|
||||
simulationResults.displacements[vi][4] = eulerAngles[1];
|
||||
simulationResults.displacements[vi][5] = eulerAngles[2];
|
||||
}
|
||||
|
||||
simulationResults.simulationModelUsed = label;
|
||||
return simulationResults;
|
||||
|
||||
// VCGEdgeMesh deformedMesh;
|
||||
// deformedMesh.copy(*(pJob->pMesh));
|
||||
// for (size_t vi = 0; vi < pJob->pMesh->VN(); vi++) {
|
||||
// const std::shared_ptr<ChNodeFEAxyzrot> node_chronos = edgeMeshVertsToChronosNodes[vi];
|
||||
// deformedMesh.vert[vi].P() = CoordType(node_chronos->GetPos()[0],
|
||||
// node_chronos->GetPos()[1],
|
||||
// node_chronos->GetPos()[2]);
|
||||
// }
|
||||
|
||||
// deformedMesh.updateEigenEdgeAndVertices();
|
||||
// deformedMesh.setLabel("deformed");
|
||||
// deformedMesh.registerForDrawing();
|
||||
// polyscope::show();
|
||||
// return simulationResults;
|
||||
}
|
||||
|
||||
void ChronosIGASimulationModel::setStructure(const std::shared_ptr<SimulationEdgeMesh> &pMesh)
|
||||
{
|
||||
mesh_chronos = convertToChronosMesh_IGA(pMesh, edgeMeshVertsToChronoNodes);
|
||||
}
|
||||
|
||||
ChronosIGASimulationModel::ChronosIGASimulationModel() {}
|
|
@ -1,39 +0,0 @@
|
|||
#ifndef CHRONOSIGASIMULATIONMODEL_HPP
|
||||
#define CHRONOSIGASIMULATIONMODEL_HPP
|
||||
|
||||
#include "simulationmodel.hpp"
|
||||
|
||||
namespace chrono {
|
||||
class ChSystemSMC;
|
||||
namespace fea {
|
||||
class ChMesh;
|
||||
class ChNodeFEAxyzrot;
|
||||
} // namespace fea
|
||||
} // namespace chrono
|
||||
|
||||
class ChronosIGASimulationModel : public SimulationModel
|
||||
{
|
||||
std::shared_ptr<chrono::fea::ChMesh> mesh_chronos;
|
||||
std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>> edgeMeshVertsToChronoNodes;
|
||||
|
||||
static void parseConstrainedVertices(
|
||||
const std::shared_ptr<const SimulationJob> &pJob,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>> &edgeMeshVertsToChronoNodes,
|
||||
chrono::ChSystemSMC &my_system);
|
||||
static void parseForces(
|
||||
const std::shared_ptr<chrono::fea::ChMesh> &mesh_chronos,
|
||||
const std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>> &edgeMeshVertsToChronoNodes,
|
||||
const std::unordered_map<VertexIndex, Vector6d> &nodalExternalForces);
|
||||
|
||||
public:
|
||||
ChronosIGASimulationModel();
|
||||
SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &pJob) override;
|
||||
void setStructure(const std::shared_ptr<SimulationEdgeMesh> &pMesh) override;
|
||||
static std::shared_ptr<chrono::fea::ChMesh> convertToChronosMesh_IGA(
|
||||
const std::shared_ptr<SimulationEdgeMesh> &pMesh,
|
||||
std::vector<std::shared_ptr<chrono::fea::ChNodeFEAxyzrot>> &edgeMeshVertsToChronosNodes);
|
||||
|
||||
inline const static std::string label{"Chronos_linear_IGA"};
|
||||
};
|
||||
|
||||
#endif // CHRONOSIGASIMULATIONMODEL_HPP
|
131
csvfile.hpp
131
csvfile.hpp
|
@ -9,43 +9,39 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CSVFile;
|
||||
class csvFile;
|
||||
|
||||
inline static CSVFile& endrow(CSVFile& file);
|
||||
inline static CSVFile& flush(CSVFile& file);
|
||||
inline static csvFile &endrow(csvFile &file);
|
||||
inline static csvFile &flush(csvFile &file);
|
||||
|
||||
class CSVFile {
|
||||
class csvFile {
|
||||
std::ofstream fs_;
|
||||
bool is_first_;
|
||||
const std::string separator_;
|
||||
const std::string escape_seq_;
|
||||
const std::string special_chars_;
|
||||
|
||||
public:
|
||||
CSVFile(const std::filesystem::path& filename,
|
||||
const bool& overwrite,
|
||||
public:
|
||||
csvFile(const std::filesystem::path &filename,
|
||||
const bool &overwrite,
|
||||
const std::string separator = ",")
|
||||
: fs_(),
|
||||
is_first_(true),
|
||||
separator_(separator),
|
||||
escape_seq_("\""),
|
||||
special_chars_("\"") {
|
||||
fs_.exceptions(std::ios::failbit | std::ios::badbit);
|
||||
if (filename.empty()) {
|
||||
fs_.copyfmt(std::cout);
|
||||
fs_.clear(std::cout.rdstate());
|
||||
fs_.basic_ios<char>::rdbuf(std::cout.rdbuf());
|
||||
} else {
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
std::ofstream outfile(filename);
|
||||
outfile.close();
|
||||
: fs_(), is_first_(true), separator_(separator), escape_seq_("\""), special_chars_("\"")
|
||||
{
|
||||
fs_.exceptions(std::ios::failbit | std::ios::badbit);
|
||||
if (filename.empty()) {
|
||||
fs_.copyfmt(std::cout);
|
||||
fs_.clear(std::cout.rdstate());
|
||||
fs_.basic_ios<char>::rdbuf(std::cout.rdbuf());
|
||||
} else {
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
std::ofstream outfile(filename);
|
||||
outfile.close();
|
||||
}
|
||||
overwrite ? fs_.open(filename, std::ios::trunc) : fs_.open(filename, std::ios::app);
|
||||
}
|
||||
overwrite ? fs_.open(filename, std::ios::trunc)
|
||||
: fs_.open(filename, std::ios::app);
|
||||
}
|
||||
}
|
||||
|
||||
~CSVFile() {
|
||||
~csvFile() {
|
||||
flush();
|
||||
fs_.close();
|
||||
}
|
||||
|
@ -57,52 +53,55 @@ class CSVFile {
|
|||
is_first_ = true;
|
||||
}
|
||||
|
||||
CSVFile& operator<<(CSVFile& (*val)(CSVFile&)) { return val(*this); }
|
||||
csvFile &operator<<(csvFile &(*val)(csvFile &)) { return val(*this); }
|
||||
|
||||
CSVFile& operator<<(const char* val) { return write(escape(val)); }
|
||||
csvFile &operator<<(const char *val) { return write(escape(val)); }
|
||||
|
||||
CSVFile& operator<<(const std::string& val) { return write(escape(val)); }
|
||||
csvFile &operator<<(const std::string &val) { return write(escape(val)); }
|
||||
|
||||
template <typename T>
|
||||
CSVFile& operator<<(const T& val) {
|
||||
return write(val);
|
||||
template<typename T>
|
||||
csvFile &operator<<(const T &val)
|
||||
{
|
||||
return write(val);
|
||||
}
|
||||
|
||||
static std::vector<std::vector<std::string>> parse(
|
||||
const std::filesystem::path& csvFilepath) {
|
||||
std::vector<std::vector<std::string>> resultCSV;
|
||||
if (!std::filesystem::exists(csvFilepath)) {
|
||||
std::cerr << "The file does not exist:" << csvFilepath.string()
|
||||
<< std::endl;
|
||||
return resultCSV;
|
||||
}
|
||||
template<typename T>
|
||||
static std::vector<std::vector<T>> parse(const std::filesystem::path &csvFilepath)
|
||||
{
|
||||
std::vector<std::vector<T>> resultCSV;
|
||||
if (!std::filesystem::exists(csvFilepath)) {
|
||||
std::cerr << "The file does not exist:" << csvFilepath.string() << std::endl;
|
||||
return resultCSV;
|
||||
}
|
||||
|
||||
std::ifstream inputfile(csvFilepath.string().c_str());
|
||||
if (!inputfile.is_open()) {
|
||||
std::cerr << "Can't open file:" << csvFilepath.string() << std::endl;
|
||||
return resultCSV;
|
||||
}
|
||||
std::vector<std::string> row;
|
||||
std::string line;
|
||||
using Tokenizer = boost::tokenizer<boost::escaped_list_separator<char>>;
|
||||
while (std::getline(inputfile, line)) {
|
||||
Tokenizer tokenizer(line);
|
||||
const int numOfCols = std::distance(tokenizer.begin(), tokenizer.end());
|
||||
row.resize(numOfCols);
|
||||
std::copy(tokenizer.begin(), tokenizer.end(), row.begin());
|
||||
// std::transform(tokenizer.begin(), tokenizer.end(),
|
||||
// row.begin(), [](const std::string &el) {
|
||||
// return boost::lexical_cast<T>(el);
|
||||
// });
|
||||
resultCSV.push_back(row);
|
||||
}
|
||||
std::ifstream inputfile(csvFilepath.string().c_str());
|
||||
if (!inputfile.is_open()) {
|
||||
std::cerr << "Can't open file:" << csvFilepath.string() << std::endl;
|
||||
return resultCSV;
|
||||
}
|
||||
std::vector<T> row;
|
||||
std::string line;
|
||||
using Tokenizer = boost::tokenizer<boost::escaped_list_separator<char>>;
|
||||
while (std::getline(inputfile, line)) {
|
||||
Tokenizer tokenizer(line);
|
||||
row.resize(std::distance(tokenizer.begin(), tokenizer.end()));
|
||||
std::transform(tokenizer.begin(), tokenizer.end(), row.begin(), [](const std::string &el) {
|
||||
return boost::lexical_cast<T>(el);
|
||||
});
|
||||
// std::cout << std::endl;
|
||||
// row.assign(tokenizer.begin(), tokenizer.end());
|
||||
// for (const auto &el : row) {
|
||||
// std::cout << el << " ";
|
||||
// }
|
||||
// std::cout << std::endl;
|
||||
resultCSV.push_back(row);
|
||||
}
|
||||
|
||||
return resultCSV;
|
||||
return resultCSV;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
CSVFile& write(const T& val) {
|
||||
private:
|
||||
template <typename T> csvFile &write(const T &val) {
|
||||
if (!is_first_) {
|
||||
fs_ << separator_;
|
||||
} else {
|
||||
|
@ -112,7 +111,7 @@ class CSVFile {
|
|||
return *this;
|
||||
}
|
||||
|
||||
std::string escape(const std::string& val) {
|
||||
std::string escape(const std::string &val) {
|
||||
std::ostringstream result;
|
||||
result << '"';
|
||||
std::string::size_type to, from = 0u, len = val.length();
|
||||
|
@ -126,14 +125,14 @@ class CSVFile {
|
|||
}
|
||||
};
|
||||
|
||||
inline static CSVFile& endrow(CSVFile& file) {
|
||||
inline static csvFile &endrow(csvFile &file) {
|
||||
file.endrow();
|
||||
return file;
|
||||
}
|
||||
|
||||
inline static CSVFile& flush(CSVFile& file) {
|
||||
inline static csvFile &flush(csvFile &file) {
|
||||
file.flush();
|
||||
return file;
|
||||
}
|
||||
|
||||
#endif // CSVFILE_HPP
|
||||
#endif // CSVFILE_HPP
|
||||
|
|
4845
der_leimer.cpp
4845
der_leimer.cpp
File diff suppressed because it is too large
Load Diff
193
der_leimer.hpp
193
der_leimer.hpp
|
@ -1,193 +0,0 @@
|
|||
#ifndef DER_LEIMER_HPP
|
||||
#define DER_LEIMER_HPP
|
||||
|
||||
//#include "ElasticRod.hh"
|
||||
#include "simulationmodel.hpp"
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
class DER_leimer : public SimulationModel
|
||||
{
|
||||
public:
|
||||
DER_leimer();
|
||||
virtual SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &pJob) override;
|
||||
struct RodParams
|
||||
{
|
||||
double thickness;
|
||||
double kstretching; //stretching stiffness
|
||||
double kbending; //bending stiffness
|
||||
double ktwist; //twisting stiffness
|
||||
double kanchorpos; //anchor positional stiffness
|
||||
double kanchordir; //anchor directional stiffness
|
||||
double rho; //density
|
||||
double restlength;
|
||||
};
|
||||
|
||||
struct RodState
|
||||
{
|
||||
Eigen::MatrixXd centerlinePositions;
|
||||
Eigen::VectorXi centerlineIndices; //"global" indices of centerline vertices
|
||||
Eigen::MatrixXd
|
||||
directors; //normal vectors to each segment. They are called "directors" here because thats how they call them in the weaving geodesics paper
|
||||
Eigen::MatrixXd matDirNormal; //Normal vector of each segment
|
||||
Eigen::MatrixXd matDirBinormal; //Binormal vector of each segment
|
||||
Eigen::VectorXd thetas;
|
||||
Eigen::MatrixXd centerlineVelocities;
|
||||
Eigen::VectorXd directorAngVel;
|
||||
Eigen::MatrixXd curvatures;
|
||||
};
|
||||
|
||||
class Rod
|
||||
{
|
||||
public:
|
||||
Rod(const RodState &startState,
|
||||
const Eigen::VectorXd &widths,
|
||||
RodParams ¶ms,
|
||||
bool isClosed);
|
||||
|
||||
enum RodVisibilityState { RS_TRANSLUCENT = 0, RS_VISIBLE, RS_HIDDEN };
|
||||
|
||||
bool isClosed() const { return isClosed_; }
|
||||
|
||||
void setVisibilityState(RodVisibilityState state) { visState_ = state; }
|
||||
RodVisibilityState visibilityState() const { return visState_; }
|
||||
|
||||
Eigen::Vector3d rodColor() const;
|
||||
Eigen::Vector3d rodColor(int seg) const;
|
||||
int rodColorID() const { return colorID_; }
|
||||
void cycleColor();
|
||||
int numVertices() const { return (int) curState.centerlinePositions.rows(); }
|
||||
int numSegments() const { return (int) curState.thetas.size(); }
|
||||
double arclength() const;
|
||||
RodState curState;
|
||||
RodState startState;
|
||||
|
||||
Eigen::VectorXd widths;
|
||||
Eigen::VectorXd restlens;
|
||||
Eigen::VectorXd masses;
|
||||
Eigen::VectorXd momInertia;
|
||||
Eigen::VectorXi segColors;
|
||||
Eigen::MatrixXd vSegParams; // stretch, bend, twist, restlength
|
||||
RodParams params;
|
||||
|
||||
void initializeRestQuantities();
|
||||
|
||||
private:
|
||||
int colorID_;
|
||||
bool isClosed_;
|
||||
RodVisibilityState visState_;
|
||||
};
|
||||
|
||||
struct Anchor
|
||||
{
|
||||
int rod;
|
||||
int seg;
|
||||
double bary; // where along the segment should the anchor be placed?[0,1]. 0 at the beginning , 1 at the end
|
||||
Eigen::Vector3d position;
|
||||
Eigen::Vector3d normal;
|
||||
double ratio; //??
|
||||
double k_pos;
|
||||
double k_dir;
|
||||
};
|
||||
|
||||
struct Intersection
|
||||
{
|
||||
int intersectionIndex;
|
||||
int globalVi;
|
||||
Eigen::MatrixXi rodSegmentIndices;
|
||||
Eigen::Matrix3d rotationMatrix;
|
||||
};
|
||||
|
||||
struct SimParams
|
||||
{
|
||||
bool allowSliding;
|
||||
Eigen::MatrixXd *anchorPoints;
|
||||
Eigen::MatrixXd *anchorNormals;
|
||||
bool gravityEnabled{true};
|
||||
Eigen::Vector3d gravityDir;
|
||||
double floorHeight;
|
||||
double floorWeight;
|
||||
};
|
||||
|
||||
class RodConfig
|
||||
{
|
||||
public:
|
||||
~RodConfig();
|
||||
|
||||
void addRod(Rod *rod);
|
||||
void addAnchor(Anchor a);
|
||||
void addIntersection(Intersection inter);
|
||||
void initWeave(); // Call after all constraints initialized
|
||||
int numRods() const { return (int) rods.size(); }
|
||||
int numAnchors() const { return (int) anchors.size(); }
|
||||
int numVertices() const { return (int) vertices.rows(); }
|
||||
int numIntersections() const { return (int) intersections.size(); }
|
||||
void reset();
|
||||
void createVisualizationMesh(Eigen::MatrixXd &Q, Eigen::MatrixXi &F);
|
||||
Eigen::Vector3d shadeRodSegment(Eigen::Vector3d light,
|
||||
int rod,
|
||||
int segment,
|
||||
bool showCover) const;
|
||||
void saveRodGeometry(const std::string &prefix);
|
||||
|
||||
std::vector<Rod *> rods;
|
||||
std::vector<Anchor> anchors;
|
||||
std::vector<Intersection> intersections;
|
||||
Eigen::MatrixXd vertices;
|
||||
|
||||
bool showConstraints;
|
||||
bool allowSliding;
|
||||
double decay; //?
|
||||
int getNumDoF() const;
|
||||
};
|
||||
|
||||
void setStructure(const std::shared_ptr<SimulationEdgeMesh> &pMesh) override;
|
||||
|
||||
private:
|
||||
bool simulateOneStepGrid(RodConfig *config);
|
||||
|
||||
void rAndJGrid(const RodConfig &config,
|
||||
Eigen::VectorXd &r,
|
||||
Eigen::SparseMatrix<double> *Jr,
|
||||
double &gravityPE,
|
||||
Eigen::VectorXd &gravityForces,
|
||||
const SimParams ¶ms,
|
||||
double &externalForcesPE,
|
||||
const Eigen::VectorXd &externalForces = Eigen::VectorXd(),
|
||||
std::vector<Eigen::Triplet<int>> *H_index = NULL,
|
||||
std::vector<double> *H_value = NULL,
|
||||
Eigen::SparseMatrix<double> *Ju = NULL,
|
||||
std::vector<Eigen::Triplet<int>> *Hu_index = NULL,
|
||||
std::vector<double> *Hu_value = NULL);
|
||||
|
||||
RodConfig *readRodGrid(const std::shared_ptr<SimulationEdgeMesh> &pMesh,
|
||||
const std::vector<int> &numVertsPerRod,
|
||||
const std::vector<int> &vInd,
|
||||
const std::vector<Eigen::Vector3d> &verts,
|
||||
const std::vector<Eigen::Vector3d> &binorms,
|
||||
const std::vector<RodParams> &rodparams,
|
||||
const std::vector<Anchor> &anchors,
|
||||
const double decay = 1.0,
|
||||
double *vStiffness = 0,
|
||||
double *restVerts = 0,
|
||||
double *restNormals = 0,
|
||||
const std::vector<double> &thetas = std::vector<double>(),
|
||||
double *eulers = 0);
|
||||
double lineSearchGrid(RodConfig &config,
|
||||
const Eigen::VectorXd &update,
|
||||
const SimParams ¶ms,
|
||||
const Eigen::VectorXd &externalForces = Eigen::VectorXd());
|
||||
SimulationResults constructSimulationResults(const std::shared_ptr<SimulationJob> &pJob,
|
||||
RodConfig *config) const;
|
||||
Eigen::Vector3d getPerpendicularVector(const Eigen::Vector3d &t) const;
|
||||
|
||||
double energy;
|
||||
Eigen::VectorXd updateVec;
|
||||
double forceResidual;
|
||||
int iter{0};
|
||||
std::shared_ptr<SimulationJob> pJob;
|
||||
|
||||
// std::unique_ptr<ElasticRod> pRod;
|
||||
};
|
||||
|
||||
Eigen::Matrix3d eulerRotation(double e0, double e1, double e2, int deriv = -1, int deriv2 = -1);
|
||||
#endif // DER_LEIMER_HPP
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,295 @@
|
|||
#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
|
||||
|
||||
struct 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 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> shouldUseTranslationalKineticEnergyThreshold;
|
||||
int gradualForcedDisplacementSteps{50};
|
||||
// int desiredGradualExternalLoadsSteps{1};
|
||||
double gamma{0.8};
|
||||
double totalResidualForcesNormThreshold{1e-8};
|
||||
double totalExternalForcesNormPercentageTermination{1e-8};
|
||||
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;
|
||||
bool useKineticDamping{true};
|
||||
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;
|
||||
};
|
||||
|
||||
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::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);
|
||||
|
||||
void reset(const std::shared_ptr<SimulationJob> &pJob);
|
||||
|
||||
public:
|
||||
DRMSimulationModel();
|
||||
SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
|
||||
const Settings &settings,
|
||||
const SimulationResults &solutionGuess = SimulationResults());
|
||||
#ifdef USE_ENSMALLEN
|
||||
double EvaluateWithGradient(const arma::mat &x, arma::mat &g);
|
||||
void setJob(const std::shared_ptr<SimulationJob> &pJob);
|
||||
SimulationMesh *getDeformedMesh(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
|
|
@ -0,0 +1,495 @@
|
|||
#include "edgemesh.hpp"
|
||||
#include "vcg/simplex/face/topology.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::getEdges()
|
||||
{
|
||||
getEdges(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() {
|
||||
getVertices(eigenVertices);
|
||||
return eigenVertices;
|
||||
}
|
||||
|
||||
Eigen::MatrixX3d VCGEdgeMesh::getEigenEdgeNormals() const {
|
||||
return eigenEdgeNormals;
|
||||
}
|
||||
|
||||
bool VCGEdgeMesh::save(const std::filesystem::__cxx11::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 (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);
|
||||
getEdges(eigenEdges);
|
||||
getVertices(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::__cxx11::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;
|
||||
}
|
||||
|
||||
getEdges(eigenEdges);
|
||||
getVertices(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 &plyFilename)
|
||||
{
|
||||
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) {
|
||||
if (vcg::tri::io::Importer<VCGEdgeMesh>::Open(*this, plyFilename.c_str(), mask) != 0) {
|
||||
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::getEdges(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
|
||||
getEdges(eigenEdges);
|
||||
getVertices(eigenVertices);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VCGEdgeMesh::copy(VCGEdgeMesh &mesh) {
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::MeshCopy(*this, mesh);
|
||||
label = mesh.getLabel();
|
||||
eigenEdges = mesh.getEigenEdges();
|
||||
if (eigenEdges.rows() == 0) {
|
||||
getEdges(eigenEdges);
|
||||
}
|
||||
eigenVertices = mesh.getEigenVertices();
|
||||
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);
|
||||
}
|
||||
|
||||
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::getVertices(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::getEdges(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
|
||||
//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, true);
|
||||
if (desiredColor.has_value()) {
|
||||
const glm::vec3 desiredColor_glm(desiredColor.value()[0],
|
||||
desiredColor.value()[1],
|
||||
desiredColor.value()[2]);
|
||||
polyscopeHandle_edgeMesh->setColor(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
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef EDGEMESH_HPP
|
||||
#define EDGEMESH_HPP
|
||||
#include "beam.hpp"
|
||||
#include "mesh.hpp"
|
||||
#include "utilities.hpp"
|
||||
#include <vcg/complex/complex.h>
|
||||
#include <vector>
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
#include <optional>
|
||||
#include <array>
|
||||
|
||||
#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 getEdges(Eigen::MatrixX2i &edges);
|
||||
void getVertices(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(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 getEdges(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> getEdges();
|
||||
|
||||
Eigen::MatrixX3d getEigenVertices();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void GeneratedRegularSquaredPattern(const double angleDeg,
|
||||
std::vector<std::vector<vcg::Point2d>> &pattern,
|
||||
const size_t &desiredNumberOfSamples);
|
||||
bool loadUsingDefaultLoader(const std::string &plyFilename);
|
||||
};
|
||||
|
||||
using VectorType = VCGEdgeMesh::CoordType;
|
||||
using CoordType = VCGEdgeMesh::CoordType;
|
||||
using VertexPointer = VCGEdgeMesh::VertexPointer;
|
||||
using EdgePointer = VCGEdgeMesh::EdgePointer;
|
||||
using ConstVCGEdgeMesh = VCGEdgeMesh;
|
||||
|
||||
#endif // EDGEMESH_HPP
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,374 +0,0 @@
|
|||
ply
|
||||
format ascii 1.0
|
||||
comment nanoply generated
|
||||
element vertex 140
|
||||
property double x
|
||||
property double y
|
||||
property double z
|
||||
property double nx
|
||||
property double ny
|
||||
property double nz
|
||||
element edge 220
|
||||
property int vertex1
|
||||
property int vertex2
|
||||
end_header
|
||||
1.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 0.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 1.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 2.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 3.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 4.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 5.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 6.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 7.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 8.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 9.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
11.000000 10.000000 0.000000 0.000000 0.000000 1.000000
|
||||
1.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
2.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
3.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
4.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
5.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
6.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
7.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
8.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
9.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
10.000000 11.000000 0.000000 0.000000 0.000000 1.000000
|
||||
0 11
|
||||
1 12
|
||||
2 13
|
||||
3 14
|
||||
4 15
|
||||
5 16
|
||||
6 17
|
||||
7 18
|
||||
8 19
|
||||
9 20
|
||||
10 11
|
||||
11 23
|
||||
11 12
|
||||
12 24
|
||||
12 13
|
||||
13 25
|
||||
13 14
|
||||
14 26
|
||||
14 15
|
||||
15 27
|
||||
15 16
|
||||
16 28
|
||||
16 17
|
||||
17 29
|
||||
17 18
|
||||
18 30
|
||||
18 19
|
||||
19 31
|
||||
19 20
|
||||
20 32
|
||||
20 21
|
||||
22 23
|
||||
23 35
|
||||
23 24
|
||||
24 36
|
||||
24 25
|
||||
25 37
|
||||
25 26
|
||||
26 38
|
||||
26 27
|
||||
27 39
|
||||
27 28
|
||||
28 40
|
||||
28 29
|
||||
29 41
|
||||
29 30
|
||||
30 42
|
||||
30 31
|
||||
31 43
|
||||
31 32
|
||||
32 44
|
||||
32 33
|
||||
34 35
|
||||
35 47
|
||||
35 36
|
||||
36 48
|
||||
36 37
|
||||
37 49
|
||||
37 38
|
||||
38 50
|
||||
38 39
|
||||
39 51
|
||||
39 40
|
||||
40 52
|
||||
40 41
|
||||
41 53
|
||||
41 42
|
||||
42 54
|
||||
42 43
|
||||
43 55
|
||||
43 44
|
||||
44 56
|
||||
44 45
|
||||
46 47
|
||||
47 59
|
||||
47 48
|
||||
48 60
|
||||
48 49
|
||||
49 61
|
||||
49 50
|
||||
50 62
|
||||
50 51
|
||||
51 63
|
||||
51 52
|
||||
52 64
|
||||
52 53
|
||||
53 65
|
||||
53 54
|
||||
54 66
|
||||
54 55
|
||||
55 67
|
||||
55 56
|
||||
56 68
|
||||
56 57
|
||||
58 59
|
||||
59 71
|
||||
59 60
|
||||
60 72
|
||||
60 61
|
||||
61 73
|
||||
61 62
|
||||
62 74
|
||||
62 63
|
||||
63 75
|
||||
63 64
|
||||
64 76
|
||||
64 65
|
||||
65 77
|
||||
65 66
|
||||
66 78
|
||||
66 67
|
||||
67 79
|
||||
67 68
|
||||
68 80
|
||||
68 69
|
||||
70 71
|
||||
71 83
|
||||
71 72
|
||||
72 84
|
||||
72 73
|
||||
73 85
|
||||
73 74
|
||||
74 86
|
||||
74 75
|
||||
75 87
|
||||
75 76
|
||||
76 88
|
||||
76 77
|
||||
77 89
|
||||
77 78
|
||||
78 90
|
||||
78 79
|
||||
79 91
|
||||
79 80
|
||||
80 92
|
||||
80 81
|
||||
82 83
|
||||
83 95
|
||||
83 84
|
||||
84 96
|
||||
84 85
|
||||
85 97
|
||||
85 86
|
||||
86 98
|
||||
86 87
|
||||
87 99
|
||||
87 88
|
||||
88 100
|
||||
88 89
|
||||
89 101
|
||||
89 90
|
||||
90 102
|
||||
90 91
|
||||
91 103
|
||||
91 92
|
||||
92 104
|
||||
92 93
|
||||
94 95
|
||||
95 107
|
||||
95 96
|
||||
96 108
|
||||
96 97
|
||||
97 109
|
||||
97 98
|
||||
98 110
|
||||
98 99
|
||||
99 111
|
||||
99 100
|
||||
100 112
|
||||
100 101
|
||||
101 113
|
||||
101 102
|
||||
102 114
|
||||
102 103
|
||||
103 115
|
||||
103 104
|
||||
104 116
|
||||
104 105
|
||||
106 107
|
||||
107 119
|
||||
107 108
|
||||
108 120
|
||||
108 109
|
||||
109 121
|
||||
109 110
|
||||
110 122
|
||||
110 111
|
||||
111 123
|
||||
111 112
|
||||
112 124
|
||||
112 113
|
||||
113 125
|
||||
113 114
|
||||
114 126
|
||||
114 115
|
||||
115 127
|
||||
115 116
|
||||
116 128
|
||||
116 117
|
||||
118 119
|
||||
119 130
|
||||
119 120
|
||||
120 131
|
||||
120 121
|
||||
121 132
|
||||
121 122
|
||||
122 133
|
||||
122 123
|
||||
123 134
|
||||
123 124
|
||||
124 135
|
||||
124 125
|
||||
125 136
|
||||
125 126
|
||||
126 137
|
||||
126 127
|
||||
127 138
|
||||
127 128
|
||||
128 139
|
||||
128 129
|
|
@ -1,69 +0,0 @@
|
|||
ply
|
||||
format ascii 1.0
|
||||
element vertex 21 { define "vertex" element, 8 of them in file }
|
||||
property float x { vertex contains float "x" coordinate }
|
||||
property float y { y coordinate is also a vertex property }
|
||||
property float z { z coordinate, too }
|
||||
property float nx
|
||||
property float ny
|
||||
property float nz
|
||||
element edge 24 { there are 6 "face" elements in the file }
|
||||
property int vertex1
|
||||
property int vertex2
|
||||
property list uchar float beam_dimensions
|
||||
property list uchar float beam_material {poissons ratio , young's modulus in GPascal}
|
||||
end_header
|
||||
|
||||
0 0 0 0 0 1
|
||||
1 0 0 0 0 1
|
||||
2 0 0 0 0 1
|
||||
3 0 0 0 0 1
|
||||
4 0 0 0 0 1
|
||||
0 1 0 0 0 1
|
||||
2 1 0 0 0 1
|
||||
4 1 0 0 0 1
|
||||
0 2 0 0 0 1
|
||||
1 2 0 0 0 1
|
||||
2 2 0 0 0 1
|
||||
3 2 0 0 0 1
|
||||
4 2 0 0 0 1
|
||||
0 3 0 0 0 1
|
||||
2 3 0 0 0 1
|
||||
4 3 0 0 0 1
|
||||
0 4 0 0 0 1
|
||||
1 4 0 0 0 1
|
||||
2 4 0 0 0 1
|
||||
3 4 0 0 0 1
|
||||
4 4 0 0 0 1
|
||||
|
||||
0 1 2 0.03 0.026 2 0.3 200
|
||||
1 2 2 0.03 0.026 2 0.3 200
|
||||
2 3 2 0.03 0.026 2 0.3 200
|
||||
3 4 2 0.03 0.026 2 0.3 200
|
||||
|
||||
0 5 2 0.03 0.026 2 0.3 200
|
||||
2 6 2 0.03 0.026 2 0.3 200
|
||||
4 7 2 0.03 0.026 2 0.3 200
|
||||
|
||||
|
||||
8 9 2 0.03 0.026 2 0.3 200
|
||||
9 10 2 0.03 0.026 2 0.3 200
|
||||
10 11 2 0.03 0.026 2 0.3 200
|
||||
11 12 2 0.03 0.026 2 0.3 200
|
||||
|
||||
8 5 2 0.03 0.026 2 0.3 200
|
||||
10 6 2 0.03 0.026 2 0.3 200
|
||||
12 7 2 0.03 0.026 2 0.3 200
|
||||
|
||||
8 13 2 0.03 0.026 2 0.3 200
|
||||
10 14 2 0.03 0.026 2 0.3 200
|
||||
12 15 2 0.03 0.026 2 0.3 200
|
||||
|
||||
16 13 2 0.03 0.026 2 0.3 200
|
||||
18 14 2 0.03 0.026 2 0.3 200
|
||||
20 15 2 0.03 0.026 2 0.3 200
|
||||
|
||||
16 17 2 0.03 0.026 2 0.3 200
|
||||
17 18 2 0.03 0.026 2 0.3 200
|
||||
18 19 2 0.03 0.026 2 0.3 200
|
||||
19 20 2 0.03 0.026 2 0.3 200
|
|
@ -1,26 +0,0 @@
|
|||
ply
|
||||
format ascii 1.0
|
||||
element vertex 5 { define "vertex" element, 8 of them in file }
|
||||
property float x { vertex contains float "x" coordinate }
|
||||
property float y { y coordinate is also a vertex property }
|
||||
property float z { z coordinate, too }
|
||||
property float nx
|
||||
property float ny
|
||||
property float nz
|
||||
element edge 4 { there are 6 "face" elements in the file }
|
||||
property int vertex1
|
||||
property int vertex2
|
||||
property list uchar float beam_dimensions
|
||||
property list uchar float beam_material {poissons ratio , young's modulus in GPascal}
|
||||
end_header
|
||||
|
||||
0 0 0 0 0 1
|
||||
1 0 0 0 0 1
|
||||
2 0 0 0 0 1
|
||||
3 0 0 0 0 1
|
||||
4 0 0 0 0 1
|
||||
|
||||
0 1 2 0.03 0.026 2 0.3 200
|
||||
1 2 2 0.03 0.026 2 0.3 200
|
||||
2 3 2 0.03 0.026 2 0.3 200
|
||||
3 4 2 0.03 0.026 2 0.3 200
|
|
@ -7,6 +7,7 @@ property float z { z coordinate, too }
|
|||
property float nx
|
||||
property float ny
|
||||
property float nz
|
||||
|
||||
element edge 4 { there are 6 "face" elements in the file }
|
||||
property int vertex1
|
||||
property int vertex2
|
||||
|
@ -23,4 +24,4 @@ end_header
|
|||
0 1 2 0.03 0.026 2 0.3 200
|
||||
1 2 2 0.03 0.026 2 0.3 200
|
||||
2 3 2 0.03 0.026 2 0.3 200
|
||||
3 4 2 0.03 0.026 2 0.3 200
|
||||
3 4 2 0.03 0.026 2 0.3 200
|
|
@ -0,0 +1,274 @@
|
|||
#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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#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
|
|
@ -0,0 +1,31 @@
|
|||
#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);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif // MESH_HPP
|
22075
nlohmann/json.hpp
22075
nlohmann/json.hpp
File diff suppressed because it is too large
Load Diff
|
@ -1,175 +0,0 @@
|
|||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.2
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <map> // map
|
||||
#include <memory> // allocator
|
||||
#include <string> // string
|
||||
#include <vector> // vector
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.2
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
// This file contains all macro definitions affecting or depending on the ABI
|
||||
|
||||
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2
|
||||
#warning "Already included a different version of the library!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum)
|
||||
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTICS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
_v ## major ## _ ## minor ## _ ## patch
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
|
||||
|
||||
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION
|
||||
#else
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
|
||||
NLOHMANN_JSON_VERSION_MINOR, \
|
||||
NLOHMANN_JSON_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
// Combine namespace components
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE
|
||||
#define NLOHMANN_JSON_NAMESPACE \
|
||||
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION)
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
|
||||
namespace nlohmann \
|
||||
{ \
|
||||
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION) \
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_END
|
||||
#define NLOHMANN_JSON_NAMESPACE_END \
|
||||
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
|
||||
} // namespace nlohmann
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
@brief namespace for Niels Lohmann
|
||||
@see https://github.com/nlohmann
|
||||
@since version 1.0.0
|
||||
*/
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
/*!
|
||||
@brief default JSONSerializer template argument
|
||||
|
||||
This serializer ignores the template arguments and uses ADL
|
||||
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||
for serialization.
|
||||
*/
|
||||
template<typename T = void, typename SFINAE = void>
|
||||
struct adl_serializer;
|
||||
|
||||
/// a class to store JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/
|
||||
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||
std::map,
|
||||
template<typename U, typename... Args> class ArrayType = std::vector,
|
||||
class StringType = std::string, class BooleanType = bool,
|
||||
class NumberIntegerType = std::int64_t,
|
||||
class NumberUnsignedType = std::uint64_t,
|
||||
class NumberFloatType = double,
|
||||
template<typename U> class AllocatorType = std::allocator,
|
||||
template<typename T, typename SFINAE = void> class JSONSerializer =
|
||||
adl_serializer,
|
||||
class BinaryType = std::vector<std::uint8_t>>
|
||||
class basic_json;
|
||||
|
||||
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/
|
||||
template<typename RefStringType>
|
||||
class json_pointer;
|
||||
|
||||
/*!
|
||||
@brief default specialization
|
||||
@sa https://json.nlohmann.me/api/json/
|
||||
*/
|
||||
using json = basic_json<>;
|
||||
|
||||
/// @brief a minimal map-like container that preserves insertion order
|
||||
/// @sa https://json.nlohmann.me/api/ordered_map/
|
||||
template<class Key, class T, class IgnoredLess, class Allocator>
|
||||
struct ordered_map;
|
||||
|
||||
/// @brief specialization that maintains the insertion order of object keys
|
||||
/// @sa https://json.nlohmann.me/api/ordered_json/
|
||||
using ordered_json = basic_json<nlohmann::ordered_map>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
|
@ -0,0 +1,296 @@
|
|||
#ifndef POLYMESH_HPP
|
||||
#define POLYMESH_HPP
|
||||
#include "mesh.hpp"
|
||||
#include "vcg/complex/complex.h"
|
||||
#include <filesystem>
|
||||
#include <wrap/io_trimesh/export_obj.h>
|
||||
#include <wrap/io_trimesh/export_ply.h>
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include <polyscope/surface_mesh.h>
|
||||
#endif
|
||||
class PFace;
|
||||
class PVertex;
|
||||
class PEdge;
|
||||
|
||||
struct PUsedTypes : public vcg::UsedTypes<vcg::Use<PVertex>::AsVertexType,
|
||||
vcg::Use<PFace>::AsFaceType,
|
||||
vcg::Use<PEdge>::AsEdgeType>
|
||||
{};
|
||||
|
||||
class PVertex : public vcg::Vertex<PUsedTypes,
|
||||
vcg::vertex::Coord3d,
|
||||
vcg::vertex::Normal3d,
|
||||
vcg::vertex::Mark,
|
||||
vcg::vertex::Qualityf,
|
||||
vcg::vertex::BitFlags,
|
||||
vcg::vertex::VFAdj,
|
||||
vcg::vertex::VEAdj>
|
||||
{};
|
||||
class PEdge : public vcg::Edge<PUsedTypes,
|
||||
vcg::edge::VertexRef,
|
||||
vcg::edge::BitFlags,
|
||||
vcg::edge::EEAdj,
|
||||
vcg::edge::EFAdj,
|
||||
vcg::edge::VEAdj,
|
||||
vcg::edge::EVAdj>
|
||||
{};
|
||||
|
||||
class PFace : public vcg::Face<PUsedTypes,
|
||||
vcg::face::PolyInfo // this is necessary if you use component in
|
||||
// vcg/simplex/face/component_polygon.h
|
||||
// It says "this class is a polygon and the memory for its components
|
||||
// (e.g. pointer to its vertices will be allocated dynamically")
|
||||
,
|
||||
// vcg::face::FHAdj,
|
||||
vcg::face::PVFAdj,
|
||||
vcg::face::PFEAdj,
|
||||
vcg::face::PFVAdj,
|
||||
vcg::face::PVFAdj,
|
||||
// vcg::face::PVFAdj,
|
||||
vcg::face::PFFAdj // Pointer to edge-adjacent face (just like FFAdj )
|
||||
,
|
||||
vcg::face::BitFlags // bit flags
|
||||
,
|
||||
vcg::face::Qualityf // quality
|
||||
,
|
||||
vcg::face::Normal3f // normal
|
||||
,
|
||||
vcg::face::Color4b>
|
||||
{};
|
||||
|
||||
class VCGPolyMesh
|
||||
: public vcg::tri::TriMesh<std::vector<PVertex>, std::vector<PFace>, std::vector<PEdge>>,
|
||||
public Mesh
|
||||
{
|
||||
public:
|
||||
virtual bool load(const std::filesystem::__cxx11::path &meshFilePath) override
|
||||
{
|
||||
int mask;
|
||||
vcg::tri::io::Importer<VCGPolyMesh>::LoadMask(meshFilePath.c_str(), mask);
|
||||
int error = vcg::tri::io::Importer<VCGPolyMesh>::Open(*this, meshFilePath.c_str(), mask);
|
||||
if (error != 0) {
|
||||
std::cerr << "Could not load polygonal mesh:" << meshFilePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::FaceFace(*this);
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::VertexEdge(*this);
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::VertexFace(*this);
|
||||
vcg::tri::UpdateNormal<VCGPolyMesh>::PerVertexNormalized(*this);
|
||||
vcg::tri::Clean<VCGPolyMesh>::RemoveUnreferencedVertex(*this);
|
||||
//finally remove valence 1 vertices on the border
|
||||
// vcg::PolygonalAlgorithm<PolyMeshType>::RemoveValence2Vertices(dual);
|
||||
return true;
|
||||
}
|
||||
// // vcg::tri::io::ImporterOBJ<VCGPolyMesh>::Open();
|
||||
// // unsigned int mask = 0;
|
||||
// // mask |= nanoply::NanoPlyWrapper<VCGPolyMesh>::IO_VERTCOORD;
|
||||
// // mask |= nanoply::NanoPlyWrapper<VCGPolyMesh>::IO_VERTNORMAL;
|
||||
// // mask |= nanoply::NanoPlyWrapper<VCGPolyMesh>::IO_VERTCOLOR;
|
||||
// // mask |= nanoply::NanoPlyWrapper<VCGPolyMesh>::IO_EDGEINDEX;
|
||||
// // mask |= nanoply::NanoPlyWrapper<VCGPolyMesh>::IO_FACEINDEX;
|
||||
// // if (nanoply::NanoPlyWrapper<VCGPolyMesh>::LoadModel(
|
||||
// // std::filesystem::absolute(filename).c_str(), *this, mask) !=
|
||||
// // 0) {
|
||||
// // std::cout << "Could not load tri mesh" << std::endl;
|
||||
// // }
|
||||
// }
|
||||
Eigen::MatrixX3d getVertices() const
|
||||
{
|
||||
Eigen::MatrixX3d vertices(VN(), 3);
|
||||
for (size_t vi = 0; vi < VN(); vi++) {
|
||||
VCGPolyMesh::CoordType vertexCoordinates = vert[vi].cP();
|
||||
vertices.row(vi) = vertexCoordinates.ToEigenVector<Eigen::Vector3d>();
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
std::vector<std::vector<int>> getFaces() const
|
||||
{
|
||||
std::vector<std::vector<int>> faces(FN());
|
||||
for (const VCGPolyMesh::FaceType &f : this->face) {
|
||||
const int fi = vcg::tri::Index<VCGPolyMesh>(*this, f);
|
||||
for (size_t vi = 0; vi < f.VN(); vi++) {
|
||||
const size_t viGlobal = vcg::tri::Index<VCGPolyMesh>(*this, f.cV(vi));
|
||||
faces[fi].push_back(viGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
return faces;
|
||||
}
|
||||
|
||||
// bool load(const std::filesystem::__cxx11::path &meshFilePath)
|
||||
// {
|
||||
// const std::string extension = ".ply";
|
||||
// std::filesystem::path filePath = meshFilePath;
|
||||
// assert(std::filesystem::path(filePath).extension().string() == extension);
|
||||
// unsigned int mask = 0;
|
||||
// mask |= vcg::tri::io::Mask::IOM_VERTCOORD;
|
||||
// mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
|
||||
// mask |= vcg::tri::io::Mask::IOM_FACEINDEX;
|
||||
// mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
|
||||
// if (vcg::tri::io::Importer<VCGPolyMesh>::Open(*this, filePath.c_str()) != 0) {
|
||||
// return false;
|
||||
// }
|
||||
// label = meshFilePath.filename();
|
||||
// return true;
|
||||
// }
|
||||
|
||||
bool save(const std::filesystem::__cxx11::path &meshFilePath = std::filesystem::path())
|
||||
{
|
||||
if (meshFilePath.extension() == ".obj") {
|
||||
return saveOBJ(meshFilePath);
|
||||
} else if (meshFilePath.extension() == ".ply") {
|
||||
return savePLY(meshFilePath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveOBJ(const std::filesystem::path &objFilePath = std::filesystem::path())
|
||||
{
|
||||
const std::string extension = ".obj";
|
||||
std::filesystem::path filePath = objFilePath;
|
||||
if (filePath.empty()) {
|
||||
filePath = std::filesystem::current_path().append(getLabel() + extension).string();
|
||||
} else if (std::filesystem::is_directory(std::filesystem::path(objFilePath))) {
|
||||
filePath = std::filesystem::path(objFilePath).append(getLabel() + extension).string();
|
||||
}
|
||||
assert(std::filesystem::path(filePath).extension().string() == extension);
|
||||
unsigned int mask = 0;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTCOORD;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
|
||||
mask |= vcg::tri::io::Mask::IOM_FACEINDEX;
|
||||
mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
|
||||
if (vcg::tri::io::ExporterOBJ<VCGPolyMesh>::Save(*this, filePath.string().c_str(), mask) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool savePLY(const std::filesystem::path &objFilePath = std::filesystem::path())
|
||||
{
|
||||
const std::string extension = ".ply";
|
||||
std::filesystem::path filePath = objFilePath;
|
||||
if (filePath.empty()) {
|
||||
filePath = std::filesystem::current_path().append(getLabel() + extension).string();
|
||||
} else if (std::filesystem::is_directory(std::filesystem::path(objFilePath))) {
|
||||
filePath = std::filesystem::path(objFilePath).append(getLabel() + extension).string();
|
||||
}
|
||||
assert(std::filesystem::path(filePath).extension().string() == extension);
|
||||
unsigned int mask = 0;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTCOORD;
|
||||
mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
|
||||
mask |= vcg::tri::io::Mask::IOM_FACEINDEX;
|
||||
mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
|
||||
if (vcg::tri::io::ExporterPLY<VCGPolyMesh>::Save(*this, filePath.string().c_str(), mask, false) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
polyscope::SurfaceMesh *registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor = std::nullopt,
|
||||
const bool &shouldEnable = true)
|
||||
{
|
||||
auto vertices = getVertices();
|
||||
auto faces = getFaces();
|
||||
PolyscopeInterface::init();
|
||||
|
||||
polyscope::SurfaceMesh *polyscopeHandle_mesh = polyscope::registerSurfaceMesh(label,
|
||||
vertices,
|
||||
faces);
|
||||
|
||||
const double drawingRadius = 0.002;
|
||||
polyscopeHandle_mesh->setEnabled(shouldEnable);
|
||||
polyscopeHandle_mesh->setEdgeWidth(drawingRadius);
|
||||
|
||||
if (desiredColor.has_value()) {
|
||||
const glm::vec3 desiredColor_glm(desiredColor.value()[0],
|
||||
desiredColor.value()[1],
|
||||
desiredColor.value()[2]);
|
||||
polyscopeHandle_mesh->setSurfaceColor(glm::normalize(desiredColor_glm));
|
||||
}
|
||||
|
||||
return polyscopeHandle_mesh;
|
||||
}
|
||||
#endif
|
||||
void moveToCenter()
|
||||
{
|
||||
CoordType centerOfMass(0, 0, 0);
|
||||
|
||||
for (int vi = 0; vi < VN(); vi++) {
|
||||
centerOfMass += vert[vi].cP();
|
||||
}
|
||||
centerOfMass /= VN();
|
||||
vcg::tri::UpdatePosition<VCGPolyMesh>::Translate(*this, -centerOfMass);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the average distance from the center of each edge to the center of its face over the whole mesh
|
||||
* */
|
||||
double getAverageFaceRadius() const
|
||||
{
|
||||
double averageFaceRadius = 0;
|
||||
for (int fi = 0; fi < FN(); fi++) {
|
||||
const VCGPolyMesh::FaceType &f = face[fi];
|
||||
CoordType centerOfFace(0, 0, 0);
|
||||
for (int vi = 0; vi < f.VN(); vi++) {
|
||||
centerOfFace = centerOfFace + f.cP(vi);
|
||||
}
|
||||
centerOfFace /= f.VN();
|
||||
|
||||
double faceRadius = 0;
|
||||
// for (int face_ei = 0; face_ei < f.EN(); face_ei++) {
|
||||
// std::cout << "fi:" << getIndex(f) << std::endl;
|
||||
// auto vps = f.FVp(0);
|
||||
// auto vpe = vps;
|
||||
for (int i = 0; i < f.VN(); i++) {
|
||||
faceRadius += vcg::Distance(centerOfFace, (f.cP0(i) + f.cP1(i)) / 2);
|
||||
}
|
||||
|
||||
// }
|
||||
const int faceEdges = f.VN(); //NOTE: When does this not hold?
|
||||
faceRadius /= faceEdges;
|
||||
averageFaceRadius += faceRadius;
|
||||
}
|
||||
averageFaceRadius /= FN();
|
||||
return averageFaceRadius;
|
||||
}
|
||||
|
||||
bool copy(VCGPolyMesh ©From)
|
||||
{
|
||||
vcg::tri::Append<VCGPolyMesh, VCGPolyMesh>::MeshCopy(*this, copyFrom);
|
||||
label = copyFrom.getLabel();
|
||||
// eigenEdges = mesh.getEigenEdges();
|
||||
// if (eigenEdges.rows() == 0) {
|
||||
// getEdges(eigenEdges);
|
||||
// }
|
||||
// eigenVertices = mesh.getEigenVertices();
|
||||
// if (eigenVertices.rows() == 0) {
|
||||
// getVertices();
|
||||
// }
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::VertexEdge(*this);
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::VertexFace(*this);
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::FaceFace(*this);
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::AllocateEdge(*this);
|
||||
vcg::tri::UpdateTopology<VCGPolyMesh>::EdgeEdge(*this);
|
||||
// vcg::tri::UpdateTopology<VCGPolyMesh>::VertexFace(*this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
VCGPolyMesh(VCGPolyMesh ©From) { copy(copyFrom); }
|
||||
VCGPolyMesh() {}
|
||||
template<typename MeshElement>
|
||||
size_t getIndex(const MeshElement &meshElement) const
|
||||
{
|
||||
return vcg::tri::Index<VCGPolyMesh>(*this, meshElement);
|
||||
}
|
||||
};
|
||||
|
||||
using ConstVCGPolyMesh = VCGPolyMesh;
|
||||
|
||||
#endif // POLYMESH_HPP
|
|
@ -1,94 +0,0 @@
|
|||
#include "reducedmodel.hpp"
|
||||
|
||||
ReducedModel::ReducedModel() : PatternGeometry({1, 0, 0, 2, 1, 2, 1}, {{0, 3}})
|
||||
|
||||
{
|
||||
interfaceNodeIndex = 3;
|
||||
label = "ReducedModel";
|
||||
// constexpr double initialHexSize = 0.3;
|
||||
// CoordType movableVertex_barycentric(1 - initialHexSize, initialHexSize / 2, initialHexSize / 2);
|
||||
// const vcg::Triangle3<double> &baseTriangle = getBaseTriangle();
|
||||
// vert[0].P() = baseTriangle.cP(0) * movableVertex_barycentric[0]
|
||||
// + baseTriangle.cP(1) * movableVertex_barycentric[1]
|
||||
// + baseTriangle.cP(2) * movableVertex_barycentric[2];
|
||||
}
|
||||
|
||||
void ReducedModel::updateBaseTriangleGeometry_theta(const double &newTheta_deg)
|
||||
{
|
||||
const CoordType baseTriangleHexagonVertexPosition = vert[0].cP();
|
||||
|
||||
const CoordType thetaRotatedHexagonBaseTriangleVertexPosition
|
||||
= vcg::RotationMatrix(PatternGeometry::DefaultNormal, vcg::math::ToRad(newTheta_deg))
|
||||
* baseTriangleHexagonVertexPosition;
|
||||
vert[0].P() = thetaRotatedHexagonBaseTriangleVertexPosition;
|
||||
|
||||
// constexpr int fanSize = 6;
|
||||
// for (int rotationCounter = 0; rotationCounter < /*ReducedModelOptimizer::*/ fanSize;
|
||||
// rotationCounter++) {
|
||||
// vert[2 * rotationCounter].P() = vcg::RotationMatrix(PatternGeometry::DefaultNormal,
|
||||
// vcg::math::ToRad(60.0 * rotationCounter))
|
||||
// * thetaRotatedHexagonBaseTriangleVertexPosition;
|
||||
// }
|
||||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
|
||||
void ReducedModel::updateBaseTriangleGeometry_R(const double &newR)
|
||||
{
|
||||
const CoordType barycentricCoordinates_hexagonBaseTriangleVertex(1 - newR, newR / 2, newR / 2);
|
||||
const vcg::Triangle3<double> &baseTriangle = getBaseTriangle();
|
||||
const CoordType hexagonBaseTriangleVertexPosition
|
||||
= baseTriangle.cP(0) * barycentricCoordinates_hexagonBaseTriangleVertex[0]
|
||||
+ baseTriangle.cP(1) * barycentricCoordinates_hexagonBaseTriangleVertex[1]
|
||||
+ baseTriangle.cP(2) * barycentricCoordinates_hexagonBaseTriangleVertex[2];
|
||||
vert[0].P() = hexagonBaseTriangleVertexPosition;
|
||||
|
||||
// constexpr int fanSize = 6;
|
||||
// for (int rotationCounter = 0; rotationCounter < /*ReducedModelOptimizer::*/ fanSize;
|
||||
// rotationCounter++) {
|
||||
// vert[2 * rotationCounter].P() = vcg::RotationMatrix(PatternGeometry::DefaultNormal,
|
||||
// vcg::math::ToRad(60.0 * rotationCounter))
|
||||
// * hexagonBaseTriangleVertexPosition;
|
||||
// // std::cout << vert[2 * rotationCounter].P()[0] << " " << vert[2 * rotationCounter].P()[1]
|
||||
// // << " " << vert[2 * rotationCounter].P()[2] << std::endl;
|
||||
// }
|
||||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
|
||||
void ReducedModel::updateBaseTriangleGeometry_theta(
|
||||
const double &newTheta_deg, std::shared_ptr<VCGEdgeMesh> &pReducedModel_edgeMesh)
|
||||
{
|
||||
std::dynamic_pointer_cast<ReducedModel>(pReducedModel_edgeMesh)
|
||||
->updateBaseTriangleGeometry_theta(newTheta_deg);
|
||||
}
|
||||
|
||||
void ReducedModel::updateBaseTriangleGeometry_R(const double &newR,
|
||||
std::shared_ptr<VCGEdgeMesh> &pReducedModel_edgeMesh)
|
||||
{
|
||||
std::dynamic_pointer_cast<ReducedModel>(pReducedModel_edgeMesh)
|
||||
->updateBaseTriangleGeometry_R(newR);
|
||||
}
|
||||
|
||||
void ReducedModel::createFan(const size_t &fanSize)
|
||||
{
|
||||
deleteDanglingVertices();
|
||||
PatternGeometry rotatedPattern;
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::MeshCopy(rotatedPattern, *this);
|
||||
for (int rotationCounter = 1; rotationCounter < fanSize; rotationCounter++) {
|
||||
vcg::Matrix44d R;
|
||||
auto rotationAxis = PatternGeometry::DefaultNormal;
|
||||
R.SetRotateDeg(360.0 / fanSize, rotationAxis);
|
||||
vcg::tri::UpdatePosition<PatternGeometry>::Matrix(rotatedPattern, R);
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::Mesh(*this, rotatedPattern);
|
||||
//For the reduced model we also need to connect to neighbouring base triangles of the fan
|
||||
if (rotationCounter == fanSize - 1) {
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(*this,
|
||||
0,
|
||||
this->VN() - rotatedPattern.VN());
|
||||
}
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(*this,
|
||||
this->VN() - 2 * rotatedPattern.VN(),
|
||||
this->VN() - rotatedPattern.VN());
|
||||
removeDuplicateVertices();
|
||||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef REDUCEDMODEL_HPP
|
||||
#define REDUCEDMODEL_HPP
|
||||
|
||||
#include "trianglepatterngeometry.hpp"
|
||||
|
||||
class ReducedModel : public PatternGeometry
|
||||
{
|
||||
|
||||
public:
|
||||
ReducedModel();
|
||||
void updateBaseTriangleGeometry_theta(const double &newTheta_deg);
|
||||
void updateBaseTriangleGeometry_R(const double &newR);
|
||||
static void updateBaseTriangleGeometry_theta(
|
||||
const double &newTheta_deg, std::shared_ptr<VCGEdgeMesh> &pReducedModel_edgeMesh);
|
||||
static void updateBaseTriangleGeometry_R(const double &newR,
|
||||
std::shared_ptr<VCGEdgeMesh> &pReducedModel_edgeMesh);
|
||||
void createFan(const size_t &fanSize = 6) override;
|
||||
};
|
||||
|
||||
#endif // REDUCEDMODEL_HPP
|
File diff suppressed because it is too large
Load Diff
|
@ -2,250 +2,13 @@
|
|||
#define REDUCEDMODELEVALUATOR_HPP
|
||||
|
||||
#include "reducedmodeloptimizer_structs.hpp"
|
||||
#include "utilities.hpp"
|
||||
|
||||
class ReducedModelEvaluator {
|
||||
public:
|
||||
enum CSVExportingDirection { Vertical = 0, Horizontal };
|
||||
enum CSVExportingData {
|
||||
raw_drm2Reduced = 0,
|
||||
norm_groundTruth2Reduced,
|
||||
raw_and_norm_drm2Reduced,
|
||||
NumberOfDataTypes
|
||||
};
|
||||
inline static std::array<std::string, NumberOfDataTypes>
|
||||
csvExportingDataStrings{"raw_drm2Reduced", "norm_drm2Reduced",
|
||||
"raw_and_norm_drm2Reduced"};
|
||||
struct ExportingSettings {
|
||||
// exporting settings
|
||||
CSVExportingDirection direction{Horizontal};
|
||||
CSVExportingData data{norm_groundTruth2Reduced};
|
||||
bool shouldWriteHeader{true};
|
||||
std::string resultsLabel;
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
bool shouldDraw{false};
|
||||
#endif
|
||||
bool shouldRecomputeGroundTruthResults{false};
|
||||
bool beVerbose{true};
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(
|
||||
Settings,
|
||||
shouldRecomputeGroundTruthResults,
|
||||
beVerbose
|
||||
//#ifdef POLYSCOPE_DEFINED
|
||||
// ,
|
||||
// shouldDraw
|
||||
|
||||
//#endif
|
||||
)
|
||||
bool save(const std::filesystem::path& jsonFilePath) const;
|
||||
bool load(const std::filesystem::path& jsonFilePath);
|
||||
std::string toString() const {
|
||||
nlohmann::json json = *this;
|
||||
return std::string("Reduced model evaluation settings:" + json.dump());
|
||||
}
|
||||
};
|
||||
|
||||
inline static constexpr int NumberOfEvaluationScenarios = 17;
|
||||
inline static const std::array<std::string, NumberOfEvaluationScenarios>
|
||||
scenariosTestSetLabels{
|
||||
"22Hex_randomBending0",
|
||||
"22Hex_randomBending1",
|
||||
"22Hex_randomBending2",
|
||||
"22Hex_randomBending4",
|
||||
"22Hex_randomBending5",
|
||||
"22Hex_randomBending8",
|
||||
"22Hex_randomBending9",
|
||||
"22Hex_randomBending11",
|
||||
"22Hex_randomBending12",
|
||||
"22Hex_randomBending16",
|
||||
"22Hex_randomBending17",
|
||||
"22Hex_randomBending18",
|
||||
"22Hex_randomBending19",
|
||||
"22Hex_bending_0.01N",
|
||||
"22Hex_pullOppositeVerts_0.05N",
|
||||
"22Hex_cylinder_0.1N",
|
||||
"22Hex_s_0.05N",
|
||||
};
|
||||
inline static constexpr double forceScalingFactor = 1.5;
|
||||
struct Results {
|
||||
std::array<double, NumberOfEvaluationScenarios> distances_drm2reduced;
|
||||
std::array<double, NumberOfEvaluationScenarios>
|
||||
distances_normalizedGroundTruth2reduced;
|
||||
std::array<std::string, NumberOfEvaluationScenarios>
|
||||
evaluationScenarioLabels;
|
||||
std::array<double, NumberOfEvaluationScenarios> maxDisplacements;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Results,
|
||||
evaluationScenarioLabels,
|
||||
maxDisplacements)
|
||||
|
||||
inline static std::string defaultFileName{"evaluationResults.json"};
|
||||
void save(const std::filesystem::path& saveToPath) {
|
||||
assert(std::filesystem::is_directory(saveToPath));
|
||||
nlohmann::json json = *this;
|
||||
std::filesystem::path jsonFilePath(
|
||||
std::filesystem::path(saveToPath).append(defaultFileName));
|
||||
std::ofstream jsonFile(jsonFilePath.string());
|
||||
jsonFile << json;
|
||||
jsonFile.close();
|
||||
}
|
||||
};
|
||||
ReducedModelEvaluator();
|
||||
Results evaluateReducedModel(
|
||||
ReducedModelOptimization::Results& optimizationResult,
|
||||
const std::filesystem::path& scenariosDirectoryPath,
|
||||
// const std::filesystem::path &reducedPatternFilePath,
|
||||
const std::filesystem::path& fullPatternTessellatedResultsDirectoryPath,
|
||||
const ReducedModelEvaluator::Settings& settings);
|
||||
Results evaluateReducedModel(
|
||||
ReducedModelOptimization::Results& optimizationResult,
|
||||
const Settings& settings);
|
||||
static void printResultsVertically(
|
||||
const ReducedModelEvaluator::Results& evaluationResults,
|
||||
CSVFile& csvOutput);
|
||||
static void printResults(
|
||||
const ReducedModelEvaluator::Results& evaluationResults,
|
||||
const std::string& resultsLabel);
|
||||
static void printResultsHorizontally(const Results& evaluationResults,
|
||||
CSVFile& csvOutput);
|
||||
static void printResults(const Results& evaluationResults,
|
||||
const ExportingSettings& exportingSettings,
|
||||
CSVFile& csvOutput);
|
||||
static void printHeader(const ExportingSettings& exportingSettings,
|
||||
CSVFile& csvOutput);
|
||||
// static double evaluateOptimizationSettings(
|
||||
// const ReducedModelOptimization::Settings &optimizationSettings,
|
||||
// const std::vector<std::shared_ptr<PatternGeometry>> &pPatterns,
|
||||
// std::vector<ReducedModelEvaluator::Results>
|
||||
// &patternEvaluationResults);
|
||||
std::shared_ptr<VCGPolyMesh> pTileIntoSurface;
|
||||
ReducedModelOptimization::Colors::RGBColor color_tesselatedPatterns{
|
||||
24.0 / 255, 23.0 / 255, 23.0 / 255};
|
||||
ReducedModelOptimization::Colors::RGBColor color_tesselatedReducedModels{
|
||||
67.0 / 255, 160.00 / 255, 232.0 / 255};
|
||||
ReducedModelOptimization::Colors::RGBColor color_tileIntoSurface{
|
||||
// 222 / 255.0, 235 / 255.0, 255 / 255.0};
|
||||
156 / 255.0, 195 / 255.0, 254 / 255.0};
|
||||
ReducedModelOptimization::Colors::RGBColor interfaceNodes_color{
|
||||
63.0 / 255, 85.0 / 255, 42.0 / 255};
|
||||
inline static constexpr char* tileIntoSurfaceFileContent = R"~(OFF
|
||||
46 66 0
|
||||
-0.0745923 0.03573945 0
|
||||
-0.07464622 0.02191801 0
|
||||
-0.06264956 0.02878203 0
|
||||
-0.08658896 0.02887542 0
|
||||
-0.06270347 0.01496059 0
|
||||
-0.06259564 0.04260346 0
|
||||
-0.08664289 0.01505398 0
|
||||
-0.08653505 0.04269686 0
|
||||
-0.0507068 0.02182462 0
|
||||
-0.07453838 0.04956088 0
|
||||
-0.05065288 0.03564605 0
|
||||
-0.09858564 0.02201139 0
|
||||
-0.09853172 0.03583283 0
|
||||
-0.06254172 0.0564249 0
|
||||
-0.05059896 0.04946748 0
|
||||
-0.08648112 0.0565183 0
|
||||
-0.09847781 0.04965428 0
|
||||
-0.03871013 0.02868864 0
|
||||
-0.07448447 0.06338232 0
|
||||
-0.03865621 0.04251007 0
|
||||
-0.1105284 0.02896881 0
|
||||
-0.1104745 0.04279025 0
|
||||
-0.03876406 0.0148672 0
|
||||
-0.05054504 0.06328891 0
|
||||
-0.0624878 0.07024634 0
|
||||
-0.03860229 0.0563315 0
|
||||
-0.1105823 0.01514738 0
|
||||
-0.08642721 0.07033974 0
|
||||
-0.09842389 0.06347572 0
|
||||
-0.1104206 0.05661169 0
|
||||
-0.07443054 0.07720376 0
|
||||
-0.05049112 0.07711035 0
|
||||
-0.03854837 0.07015293 0
|
||||
-0.06243387 0.08406778 0
|
||||
-0.08637329 0.08416118 0
|
||||
-0.09836997 0.07729716 0
|
||||
-0.1103666 0.07043312 0
|
||||
-0.07437663 0.09102518 0
|
||||
-0.03849445 0.08397438 0
|
||||
-0.0504372 0.0909318 0
|
||||
-0.06237995 0.09788923 0
|
||||
-0.08631937 0.09798261 0
|
||||
-0.09831604 0.09111859 0
|
||||
-0.1103127 0.08425456 0
|
||||
-0.03844052 0.09779582 0
|
||||
-0.1102588 0.09807601 0
|
||||
3 0 1 2
|
||||
3 3 1 0
|
||||
3 4 2 1
|
||||
3 5 0 2
|
||||
3 3 6 1
|
||||
3 3 0 7
|
||||
3 8 2 4
|
||||
3 5 9 0
|
||||
3 10 5 2
|
||||
3 3 11 6
|
||||
3 7 0 9
|
||||
3 12 3 7
|
||||
3 10 2 8
|
||||
3 5 13 9
|
||||
3 10 14 5
|
||||
3 12 11 3
|
||||
3 7 9 15
|
||||
3 12 7 16
|
||||
3 10 8 17
|
||||
3 14 13 5
|
||||
3 18 9 13
|
||||
3 19 14 10
|
||||
3 12 20 11
|
||||
3 18 15 9
|
||||
3 16 7 15
|
||||
3 21 12 16
|
||||
3 22 17 8
|
||||
3 19 10 17
|
||||
3 23 13 14
|
||||
3 18 13 24
|
||||
3 19 25 14
|
||||
3 21 20 12
|
||||
3 26 11 20
|
||||
3 18 27 15
|
||||
3 16 15 28
|
||||
3 21 16 29
|
||||
3 23 24 13
|
||||
3 23 14 25
|
||||
3 30 18 24
|
||||
3 30 27 18
|
||||
3 15 27 28
|
||||
3 29 16 28
|
||||
3 23 31 24
|
||||
3 23 25 32
|
||||
3 30 24 33
|
||||
3 30 34 27
|
||||
3 35 28 27
|
||||
3 29 28 36
|
||||
3 23 32 31
|
||||
3 24 31 33
|
||||
3 30 33 37
|
||||
3 30 37 34
|
||||
3 35 27 34
|
||||
3 35 36 28
|
||||
3 32 38 31
|
||||
3 33 31 39
|
||||
3 40 37 33
|
||||
3 34 37 41
|
||||
3 35 34 42
|
||||
3 35 43 36
|
||||
3 38 39 31
|
||||
3 40 33 39
|
||||
3 34 41 42
|
||||
3 35 42 43
|
||||
3 44 39 38
|
||||
3 45 43 42
|
||||
)~";
|
||||
class ReducedModelEvaluator
|
||||
{
|
||||
public:
|
||||
ReducedModelEvaluator();
|
||||
static std::vector<double> evaluateReducedModel(
|
||||
ReducedModelOptimization::Results &optimizationResults);
|
||||
};
|
||||
|
||||
#endif // REDUCEDMODELEVALUATOR_HPP
|
||||
#endif // REDUCEDMODELEVALUATOR_HPP
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,417 +0,0 @@
|
|||
#ifndef REDUCEDMODELOPTIMIZER_HPP
|
||||
#define REDUCEDMODELOPTIMIZER_HPP
|
||||
|
||||
//#include "csvfile.hpp"
|
||||
#include "drmsimulationmodel.hpp"
|
||||
#include "edgemesh.hpp"
|
||||
#include "linearsimulationmodel.hpp"
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include "matplot/matplot.h"
|
||||
#endif
|
||||
#include <Eigen/Dense>
|
||||
#include "reducedmodel.hpp"
|
||||
#include "reducedmodeloptimizer_structs.hpp"
|
||||
#include "simulationmesh.hpp"
|
||||
#ifdef DLIB_DEFINED
|
||||
#include <dlib/global_optimization.h>
|
||||
#include <dlib/optimization.h>
|
||||
#endif
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include "polyscope/color_management.h"
|
||||
#endif // POLYSCOPE_DEFINED
|
||||
using PatternVertexIndex = VertexIndex;
|
||||
using ReducedModelVertexIndex = VertexIndex;
|
||||
|
||||
class ReducedModelOptimizer {
|
||||
public:
|
||||
struct OptimizationState {
|
||||
std::vector<SimulationResults> fullPatternResults;
|
||||
std::vector<double> translationalDisplacementNormalizationValues;
|
||||
std::vector<double> rotationalDisplacementNormalizationValues;
|
||||
std::vector<std::shared_ptr<SimulationJob>> pSimulationJobs_pattern;
|
||||
std::vector<std::shared_ptr<SimulationJob>> simulationJobs_reducedModel;
|
||||
std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>
|
||||
reducedToFullInterfaceViMap;
|
||||
std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>
|
||||
fullPatternOppositeInterfaceViPairs;
|
||||
matplot::line_handle gPlotHandle;
|
||||
std::vector<size_t> objectiveValueHistory_iteration;
|
||||
std::vector<double> objectiveValueHistory;
|
||||
std::vector<double> plotColors;
|
||||
std::array<double,
|
||||
ReducedModelOptimization::OptimizationParameterIndex::
|
||||
NumberOfOptimizationVariables>
|
||||
parametersInitialValue;
|
||||
std::array<double,
|
||||
ReducedModelOptimization::OptimizationParameterIndex::
|
||||
NumberOfOptimizationVariables>
|
||||
optimizationInitialValue;
|
||||
std::vector<int> simulationScenarioIndices;
|
||||
double minY{DBL_MAX};
|
||||
std::vector<double> minX;
|
||||
int numOfSimulationCrashes{false};
|
||||
int numberOfFunctionCalls{0};
|
||||
// Variables for finding the full pattern simulation forces
|
||||
std::shared_ptr<SimulationEdgeMesh> pFullPatternSimulationEdgeMesh;
|
||||
std::array<std::function<void(const double& newValue,
|
||||
std::shared_ptr<SimulationEdgeMesh>&
|
||||
pReducedPatternSimulationEdgeMesh)>,
|
||||
7>
|
||||
functions_updateReducedPatternParameter;
|
||||
std::vector<double> xMin;
|
||||
std::vector<double> xMax;
|
||||
std::vector<double> scenarioWeights;
|
||||
std::vector<ReducedModelOptimization::Settings::ObjectiveWeights>
|
||||
objectiveWeights;
|
||||
std::string simulationModelLabel_reducedModel;
|
||||
};
|
||||
|
||||
private:
|
||||
OptimizationState optimizationState;
|
||||
vcg::Triangle3<double> baseTriangle;
|
||||
std::function<void(
|
||||
const double&,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&,
|
||||
SimulationJob&)>
|
||||
constructScenarioFunction;
|
||||
std::shared_ptr<SimulationEdgeMesh> m_pReducedModelSimulationEdgeMesh;
|
||||
std::shared_ptr<SimulationEdgeMesh> m_pSimulationEdgeMesh_pattern;
|
||||
std::unordered_map<PatternVertexIndex, ReducedModelVertexIndex>
|
||||
m_fullToReducedInterfaceViMap;
|
||||
std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>
|
||||
m_fullPatternOppositeInterfaceViPairs;
|
||||
std::unordered_map<size_t, size_t> nodeToSlot;
|
||||
std::unordered_map<size_t, std::unordered_set<size_t>> slotToNode;
|
||||
std::string optimizationNotes;
|
||||
std::array<
|
||||
std::function<void(
|
||||
const double&,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&,
|
||||
SimulationJob&)>,
|
||||
ReducedModelOptimization::NumberOfBaseSimulationScenarios>
|
||||
constructBaseScenarioFunctions;
|
||||
std::vector<bool> scenarioIsSymmetrical;
|
||||
int fullPatternNumberOfEdges;
|
||||
std::string fullPatternLabel;
|
||||
// ReducedModelOptimization::Settings optimizationSettings;
|
||||
|
||||
public:
|
||||
struct FunctionEvaluation {
|
||||
FunctionEvaluation() = default;
|
||||
FunctionEvaluation(const std::vector<double>& x, double y) : x(x), y(y) {}
|
||||
|
||||
std::vector<double> x;
|
||||
double y = std::numeric_limits<double>::quiet_NaN();
|
||||
};
|
||||
|
||||
// struct ParameterLabels
|
||||
// {
|
||||
// inline const static std::string E = {"E"};
|
||||
// inline const static std::string A = {"A"};
|
||||
// inline const static std::string I2 ={"I2"};
|
||||
// inline const static std::string I3 ={"I3"};
|
||||
// inline const static std::string J = {"J"};
|
||||
// inline const static std::string th= {"Theta"};
|
||||
// inline const static std::string R = {"R"};
|
||||
// };
|
||||
// inline constexpr static ParameterLabels parameterLabels();
|
||||
|
||||
inline static std::array<
|
||||
std::string,
|
||||
ReducedModelOptimization::NumberOfOptimizationVariables>
|
||||
parameterLabels = {"E", "A", "I2", "I3", "J", "Theta", "R"};
|
||||
constexpr static std::
|
||||
array<double, ReducedModelOptimization::NumberOfBaseSimulationScenarios>
|
||||
simulationScenariosResolution = {12, 12, 22, 22, 22, 22};
|
||||
// simulationScenariosResolution = {8, 8, 16, 16, 16, 16};
|
||||
// simulationScenariosResolution = {4, 4, 8, 8, 8, 8};
|
||||
// simulationScenariosResolution = {2, 2, 4, 4, 4, 4};
|
||||
// simulationScenariosResolution = {2, 2, 2, 22, 22, 22};
|
||||
// simulationScenariosResolution = {1, 1, 1, 1, 1, 1};
|
||||
constexpr static std::
|
||||
array<double, ReducedModelOptimization::NumberOfBaseSimulationScenarios>
|
||||
baseScenarioWeights = {1, 1, 2, 2, 2};
|
||||
inline static int totalNumberOfSimulationScenarios =
|
||||
std::accumulate(simulationScenariosResolution.begin(),
|
||||
simulationScenariosResolution.end(),
|
||||
0);
|
||||
inline static int fanCardinality{6};
|
||||
inline static double initialValue_R{0.5};
|
||||
inline static double initialValue_theta{0};
|
||||
int interfaceNodeIndex;
|
||||
double operator()(const Eigen::VectorXd& x, Eigen::VectorXd&) const;
|
||||
|
||||
ReducedModelOptimizer();
|
||||
static void computeReducedModelSimulationJob(
|
||||
const SimulationJob& simulationJobOfFullModel,
|
||||
const std::unordered_map<size_t, size_t>& fullToReducedMap,
|
||||
SimulationJob& simulationJobOfReducedModel);
|
||||
|
||||
SimulationJob getReducedSimulationJob(
|
||||
const SimulationJob& fullModelSimulationJob);
|
||||
|
||||
static void runSimulation(const std::string& filename,
|
||||
std::vector<double>& x);
|
||||
|
||||
static std::vector<std::shared_ptr<SimulationJob>>
|
||||
createFullPatternSimulationJobs(
|
||||
const std::shared_ptr<SimulationEdgeMesh>& pMesh,
|
||||
const std::unordered_map<size_t, size_t>&
|
||||
fullPatternOppositeInterfaceViMap);
|
||||
|
||||
static void createSimulationEdgeMeshes(
|
||||
PatternGeometry& pattern,
|
||||
PatternGeometry& reducedModel,
|
||||
const ReducedModelOptimization::Settings& optimizationSettings,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pFullPatternSimulationEdgeMesh,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh);
|
||||
void computeMaps(
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>& slotToNode,
|
||||
PatternGeometry& fullPattern,
|
||||
ReducedModel& reducedPattern,
|
||||
std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap,
|
||||
std::unordered_map<PatternVertexIndex, ReducedModelVertexIndex>&
|
||||
fullToReducedInterfaceViMap,
|
||||
std::vector<std::pair<PatternVertexIndex, ReducedModelVertexIndex>>&
|
||||
fullPatternOppositeInterfaceViMap);
|
||||
static void visualizeResults(
|
||||
const std::vector<std::shared_ptr<SimulationJob>>&
|
||||
fullPatternSimulationJobs,
|
||||
const std::vector<std::shared_ptr<SimulationJob>>&
|
||||
reducedPatternSimulationJobs,
|
||||
const std::vector<ReducedModelOptimization::BaseSimulationScenario>&
|
||||
simulationScenarios,
|
||||
const std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap);
|
||||
static void registerResultsForDrawing(
|
||||
const std::shared_ptr<SimulationJob>& pFullPatternSimulationJob,
|
||||
const std::shared_ptr<SimulationJob>& pReducedPatternSimulationJob,
|
||||
const std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap);
|
||||
|
||||
static double computeRawTranslationalError(
|
||||
const std::vector<Vector6d>& fullPatternDisplacements,
|
||||
const std::vector<Vector6d>& reducedPatternDisplacements,
|
||||
const std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap);
|
||||
|
||||
static double computeDisplacementError(
|
||||
const std::vector<Vector6d>& fullPatternDisplacements,
|
||||
const std::vector<Vector6d>& reducedPatternDisplacements,
|
||||
const std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap,
|
||||
const double& normalizationFactor);
|
||||
|
||||
static double computeRawRotationalError(
|
||||
const std::vector<Eigen::Quaterniond>& rotatedQuaternion_fullPattern,
|
||||
const std::vector<Eigen::Quaterniond>& rotatedQuaternion_reducedPattern,
|
||||
const std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap);
|
||||
|
||||
static double computeRotationalError(
|
||||
const std::vector<Eigen::Quaterniond>& rotatedQuaternion_fullPattern,
|
||||
const std::vector<Eigen::Quaterniond>& rotatedQuaternion_reducedPattern,
|
||||
const std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap,
|
||||
const double& normalizationFactor);
|
||||
static double computeError(
|
||||
const SimulationResults& simulationResults_fullPattern,
|
||||
const SimulationResults& simulationResults_reducedPattern,
|
||||
const std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>&
|
||||
reducedToFullInterfaceViMap,
|
||||
const double& normalizationFactor_translationalDisplacement,
|
||||
const double& normalizationFactor_rotationalDisplacement,
|
||||
const double& scenarioWeight,
|
||||
const ReducedModelOptimization::Settings::ObjectiveWeights&
|
||||
objectiveWeights);
|
||||
static void constructAxialSimulationScenario(
|
||||
const double& forceMagnitude,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&
|
||||
oppositeInterfaceViPairs,
|
||||
SimulationJob& job);
|
||||
|
||||
static void constructShearSimulationScenario(
|
||||
const double& forceMagnitude,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&
|
||||
oppositeInterfaceViPairs,
|
||||
SimulationJob& job);
|
||||
|
||||
static void constructBendingSimulationScenario(
|
||||
const double& forceMagnitude,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&
|
||||
oppositeInterfaceViPairs,
|
||||
SimulationJob& job);
|
||||
|
||||
static void constructDomeSimulationScenario(
|
||||
const double& forceMagnitude,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&
|
||||
oppositeInterfaceViPairs,
|
||||
SimulationJob& job);
|
||||
|
||||
static void constructSaddleSimulationScenario(
|
||||
const double& forceMagnitude,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&
|
||||
oppositeInterfaceViPairs,
|
||||
SimulationJob& job);
|
||||
static void constructSSimulationScenario(
|
||||
const double& forceMagnitude,
|
||||
const std::vector<std::pair<PatternVertexIndex, PatternVertexIndex>>&
|
||||
oppositeInterfaceViPairs,
|
||||
SimulationJob& job);
|
||||
static std::function<void(
|
||||
const std::vector<double>& x,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
function_updateReducedPattern;
|
||||
static std::function<void(
|
||||
const double& newE,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
function_updateReducedPattern_material_E;
|
||||
static std::function<void(
|
||||
const double& newA,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
function_updateReducedPattern_material_A;
|
||||
static std::function<void(
|
||||
const double& newI,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
function_updateReducedPattern_material_I;
|
||||
static std::function<void(
|
||||
const double& newI2,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
function_updateReducedPattern_material_I2;
|
||||
static std::function<void(
|
||||
const double& newI3,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
function_updateReducedPattern_material_I3;
|
||||
static std::function<void(
|
||||
const double& newJ,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
function_updateReducedPattern_material_J;
|
||||
// static double objective(const std::vector<double>& x);
|
||||
void initializeUpdateReducedPatternFunctions();
|
||||
// static double objective(const double &xValue);
|
||||
|
||||
ReducedModelOptimization::Results optimize(
|
||||
ConstPatternGeometry& fullPattern,
|
||||
const ReducedModelOptimization::Settings& optimizationSettings);
|
||||
|
||||
void optimize(ConstPatternGeometry& fullPattern,
|
||||
ReducedModelOptimization::Settings& optimizationSettings,
|
||||
ReducedModelOptimization::Results& optimizationResults);
|
||||
static double objective(
|
||||
const std::vector<double>& x,
|
||||
ReducedModelOptimizer::OptimizationState& optimizationState);
|
||||
|
||||
private:
|
||||
void optimize(
|
||||
ReducedModelOptimization::Settings& optimizationSettings,
|
||||
ReducedModelOptimization::Results& results,
|
||||
const std::vector<ReducedModelOptimization::BaseSimulationScenario>&
|
||||
simulationScenarios =
|
||||
std::vector<ReducedModelOptimization::BaseSimulationScenario>(
|
||||
{ReducedModelOptimization::Axial,
|
||||
ReducedModelOptimization::Shear,
|
||||
ReducedModelOptimization::Bending,
|
||||
ReducedModelOptimization::Dome,
|
||||
ReducedModelOptimization::Saddle,
|
||||
ReducedModelOptimization::S}));
|
||||
|
||||
void initializePatterns(
|
||||
PatternGeometry& fullPattern,
|
||||
ReducedModel& reducedModel,
|
||||
const ReducedModelOptimization::Settings& optimizationSettings);
|
||||
static void computeDesiredReducedModelDisplacements(
|
||||
const SimulationResults& fullModelResults,
|
||||
const std::unordered_map<size_t, size_t>& displacementsReducedToFullMap,
|
||||
Eigen::MatrixX3d& optimalDisplacementsOfReducedModel);
|
||||
void runOptimization(const ReducedModelOptimization::Settings& settings,
|
||||
ReducedModelOptimization::Results& results);
|
||||
void computeMaps(PatternGeometry& fullModel, ReducedModel& reducedModel);
|
||||
void createSimulationEdgeMeshes(
|
||||
PatternGeometry& fullModel,
|
||||
PatternGeometry& reducedModel,
|
||||
const ReducedModelOptimization::Settings& optimizationSettings);
|
||||
void initializeOptimizationParameters(
|
||||
const std::shared_ptr<SimulationEdgeMesh>& mesh,
|
||||
const std::array<ReducedModelOptimization::xRange,
|
||||
ReducedModelOptimization::NumberOfOptimizationVariables>&
|
||||
optimizationParamters);
|
||||
|
||||
void computeObjectiveValueNormalizationFactors(
|
||||
const ReducedModelOptimization::Settings& optimizationSettings);
|
||||
|
||||
void getResults(const FunctionEvaluation& optimalObjective,
|
||||
const ReducedModelOptimization::Settings& settings,
|
||||
ReducedModelOptimization::Results& results);
|
||||
// double computeFullPatternMaxSimulationForce(
|
||||
// const ReducedModelOptimization::BaseSimulationScenario& scenario)
|
||||
// const;
|
||||
|
||||
#ifdef DLIB_DEFINED
|
||||
static double objective(const dlib::matrix<double, 0, 1>& x);
|
||||
static double objective(const double& xValue);
|
||||
ReducedModelOptimizer::FunctionEvaluation optimizeWith_dlib(
|
||||
const std::vector<ReducedModelOptimization::OptimizationParameterIndex>&
|
||||
parameterGroup,
|
||||
const ReducedModelOptimization::Settings& settings,
|
||||
const int& totalNumberOfOptimizationParameters);
|
||||
ReducedModelOptimizer::FunctionEvaluation optimizeWith_bobyqa(
|
||||
const std::vector<ReducedModelOptimization::OptimizationParameterIndex>&
|
||||
parameterGroup,
|
||||
const ReducedModelOptimization::Settings& settings);
|
||||
#endif
|
||||
std::array<double, ReducedModelOptimization::NumberOfBaseSimulationScenarios>
|
||||
computeFullPatternMaxSimulationForces(
|
||||
const std::vector<ReducedModelOptimization::BaseSimulationScenario>&
|
||||
desiredBaseSimulationScenario) const;
|
||||
std::vector<std::shared_ptr<SimulationJob>> createFullPatternSimulationJobs(
|
||||
const std::shared_ptr<SimulationEdgeMesh>& pMesh,
|
||||
const std::array<
|
||||
double,
|
||||
ReducedModelOptimization::NumberOfBaseSimulationScenarios>&
|
||||
baseScenarioMaxForceMagnitudes) const;
|
||||
std::array<double, ReducedModelOptimization::NumberOfBaseSimulationScenarios>
|
||||
getFullPatternMaxSimulationForces(
|
||||
const std::vector<ReducedModelOptimization::BaseSimulationScenario>&
|
||||
desiredBaseSimulationScenarioIndices,
|
||||
const std::filesystem::path& intermediateResultsDirectoryPath,
|
||||
const bool& recomputeForceMagnitudes);
|
||||
std::array<double, ReducedModelOptimization::NumberOfBaseSimulationScenarios>
|
||||
getFullPatternMaxSimulationForces();
|
||||
void computeScenarioWeights(
|
||||
const std::vector<ReducedModelOptimization::BaseSimulationScenario>&
|
||||
baseSimulationScenarios,
|
||||
const ReducedModelOptimization::Settings& optimizationSettings);
|
||||
};
|
||||
inline std::function<void(
|
||||
const double& newE,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
ReducedModelOptimizer::function_updateReducedPattern_material_E;
|
||||
inline std::function<void(
|
||||
const double& newA,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
ReducedModelOptimizer::function_updateReducedPattern_material_A;
|
||||
inline std::function<void(
|
||||
const double& newI,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
ReducedModelOptimizer::function_updateReducedPattern_material_I;
|
||||
inline std::function<void(
|
||||
const double& newI2,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
ReducedModelOptimizer::function_updateReducedPattern_material_I2;
|
||||
inline std::function<void(
|
||||
const double& newI3,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
ReducedModelOptimizer::function_updateReducedPattern_material_I3;
|
||||
inline std::function<void(
|
||||
const double& newJ,
|
||||
std::shared_ptr<SimulationEdgeMesh>& pReducedPatternSimulationEdgeMesh)>
|
||||
ReducedModelOptimizer::function_updateReducedPattern_material_J;
|
||||
inline std::function<void(const std::vector<double>& x,
|
||||
std::shared_ptr<SimulationEdgeMesh>& m)>
|
||||
ReducedModelOptimizer::function_updateReducedPattern;
|
||||
|
||||
extern ReducedModelOptimizer::OptimizationState global;
|
||||
|
||||
#endif // REDUCEDMODELOPTIMIZER_HPP
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,813 @@
|
|||
#ifndef SIMULATIONSTRUCTS_HPP
|
||||
#define SIMULATIONSTRUCTS_HPP
|
||||
#include <fstream>
|
||||
|
||||
namespace Eigen {
|
||||
template <class Matrix>
|
||||
void write_binary(const std::string &filename, const Matrix &matrix) {
|
||||
std::ofstream out(filename,
|
||||
std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
typename Matrix::Index rows = matrix.rows(), cols = matrix.cols();
|
||||
out.write((char *)(&rows), sizeof(typename Matrix::Index));
|
||||
out.write((char *)(&cols), sizeof(typename Matrix::Index));
|
||||
out.write((char *)matrix.data(),
|
||||
rows * cols * sizeof(typename Matrix::Scalar));
|
||||
out.close();
|
||||
}
|
||||
template <class Matrix>
|
||||
void read_binary(const std::string &filename, Matrix &matrix) {
|
||||
std::ifstream in(filename, std::ios::in | std::ios::binary);
|
||||
typename Matrix::Index rows = 0, cols = 0;
|
||||
in.read((char *)(&rows), sizeof(typename Matrix::Index));
|
||||
in.read((char *)(&cols), sizeof(typename Matrix::Index));
|
||||
matrix.resize(rows, cols);
|
||||
in.read((char *)matrix.data(), rows * cols * sizeof(typename Matrix::Scalar));
|
||||
in.close();
|
||||
}
|
||||
//const static IOFormat CSVFormat(StreamPrecision, DontAlignCols, ", ", "\n");
|
||||
//template<class Matrix>
|
||||
//void writeToCSV(const std::string &filename, Matrix &matrix)
|
||||
//{
|
||||
// ofstream file(filename.c_str());
|
||||
// file << matrix.format(CSVFormat);
|
||||
//}
|
||||
} // namespace Eigen
|
||||
|
||||
#include "simulationmesh.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct SimulationHistory {
|
||||
SimulationHistory() {}
|
||||
|
||||
size_t numberOfSteps{0};
|
||||
std::string label;
|
||||
std::vector<double> logResidualForces;
|
||||
std::vector<double> kineticEnergy;
|
||||
std::vector<double> potentialEnergies;
|
||||
std::vector<size_t> redMarks;
|
||||
std::vector<double> greenMarks;
|
||||
std::vector<double> residualForcesMovingAverage;
|
||||
std::vector<double> sumOfNormalizedDisplacementNorms;
|
||||
// std::vector<double> residualForcesMovingAverageDerivativesLog;
|
||||
|
||||
void markRed(const size_t &stepNumber) { redMarks.push_back(stepNumber); }
|
||||
|
||||
void markGreen(const size_t &stepNumber) { greenMarks.push_back(stepNumber); }
|
||||
|
||||
void stepPulse(const SimulationMesh &mesh)
|
||||
{
|
||||
kineticEnergy.push_back(std::log10(mesh.currentTotalKineticEnergy));
|
||||
// potentialEnergy.push_back(mesh.totalPotentialEnergykN);
|
||||
logResidualForces.push_back(std::log10(mesh.totalResidualForcesNorm));
|
||||
residualForcesMovingAverage.push_back(std::log10(mesh.residualForcesMovingAverage));
|
||||
sumOfNormalizedDisplacementNorms.push_back(std::log10(mesh.sumOfNormalizedDisplacementNorms));
|
||||
// residualForcesMovingAverageDerivativesLog.push_back(
|
||||
// std::log(mesh.residualForcesMovingAverageDerivativeNorm));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
logResidualForces.clear();
|
||||
kineticEnergy.clear();
|
||||
potentialEnergies.clear();
|
||||
residualForcesMovingAverage.clear();
|
||||
sumOfNormalizedDisplacementNorms.clear();
|
||||
// residualForcesMovingAverageDerivativesLog.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace nlohmann {
|
||||
|
||||
template <> struct adl_serializer<std::unordered_map<VertexIndex, Vector6d>> {
|
||||
static void to_json(json &j,
|
||||
const std::unordered_map<VertexIndex, Vector6d> &value) {
|
||||
// calls the "to_json" method in T's namespace
|
||||
}
|
||||
|
||||
static void from_json(const nlohmann::json &j,
|
||||
std::unordered_map<VertexIndex, Vector6d> &m) {
|
||||
std::cout << "Entered." << std::endl;
|
||||
for (const auto &p : j) {
|
||||
m.emplace(p.at(0).template get<VertexIndex>(),
|
||||
p.at(1).template get<std::array<double, 6>>());
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
||||
class SimulationJob {
|
||||
// const std::unordered_map<VertexIndex, VectorType> nodalForcedNormals;
|
||||
// json labels
|
||||
struct JSONLabels {
|
||||
inline static std::string meshFilename{"mesh filename"};
|
||||
inline static std::string forcedDisplacements{"forced displacements"};
|
||||
inline static std::string constrainedVertices{"fixed vertices"};
|
||||
inline static std::string nodalForces{"forces"};
|
||||
inline static std::string label{"label"};
|
||||
inline static std::string meshLabel{
|
||||
"meshLabel"}; // TODO: should be in the savePly function of the
|
||||
// simulation mesh class
|
||||
} jsonLabels;
|
||||
|
||||
public:
|
||||
inline static std::string jsonDefaultFileName = "SimulationJob.json";
|
||||
std::shared_ptr<SimulationMesh> pMesh;
|
||||
std::string label{"empty_job"};
|
||||
std::unordered_map<VertexIndex, std::unordered_set<int>> constrainedVertices;
|
||||
std::unordered_map<VertexIndex, Vector6d> nodalExternalForces;
|
||||
std::unordered_map<VertexIndex, Eigen::Vector3d> nodalForcedDisplacements;
|
||||
SimulationJob(const std::shared_ptr<SimulationMesh> &m,
|
||||
const std::string &label,
|
||||
const std::unordered_map<VertexIndex, std::unordered_set<int>> &cv,
|
||||
const std::unordered_map<VertexIndex, Vector6d> &ef = {},
|
||||
const std::unordered_map<VertexIndex, Eigen::Vector3d> &fd = {})
|
||||
: pMesh(m), label(label), constrainedVertices(cv), nodalExternalForces(ef),
|
||||
nodalForcedDisplacements(fd)
|
||||
{}
|
||||
SimulationJob() {}
|
||||
SimulationJob(const std::string &jsonFilename) { load(jsonFilename); }
|
||||
|
||||
bool isEmpty()
|
||||
{
|
||||
return constrainedVertices.empty() && nodalExternalForces.empty()
|
||||
&& nodalForcedDisplacements.empty() && pMesh == nullptr;
|
||||
}
|
||||
void remap(const std::unordered_map<size_t, size_t> &sourceToDestinationViMap,
|
||||
SimulationJob &destination_simulationJob) const
|
||||
{
|
||||
std::unordered_map<VertexIndex, std::unordered_set<int>> destination_fixedVertices;
|
||||
for (const auto &source_fixedVertex : this->constrainedVertices) {
|
||||
destination_fixedVertices[sourceToDestinationViMap.at(source_fixedVertex.first)]
|
||||
= source_fixedVertex.second;
|
||||
}
|
||||
|
||||
std::unordered_map<VertexIndex, Vector6d> destination_nodalForces;
|
||||
for (const auto &source_nodalForces : this->nodalExternalForces) {
|
||||
destination_nodalForces[sourceToDestinationViMap.at(source_nodalForces.first)]
|
||||
= source_nodalForces.second;
|
||||
}
|
||||
|
||||
std::unordered_map<VertexIndex, Eigen::Vector3d> destination_forcedDisplacements;
|
||||
for (const auto &source_forcedDisplacements : this->nodalForcedDisplacements) {
|
||||
destination_forcedDisplacements[sourceToDestinationViMap.at(
|
||||
source_forcedDisplacements.first)]
|
||||
= source_forcedDisplacements.second;
|
||||
}
|
||||
|
||||
destination_simulationJob.constrainedVertices = destination_fixedVertices;
|
||||
destination_simulationJob.nodalExternalForces = destination_nodalForces;
|
||||
destination_simulationJob.label = this->getLabel();
|
||||
destination_simulationJob.nodalForcedDisplacements = destination_forcedDisplacements;
|
||||
}
|
||||
SimulationJob getCopy() const {
|
||||
SimulationJob jobCopy;
|
||||
jobCopy.pMesh = std::make_shared<SimulationMesh>();
|
||||
jobCopy.pMesh->copy(*pMesh);
|
||||
jobCopy.label = label;
|
||||
jobCopy.constrainedVertices = constrainedVertices;
|
||||
jobCopy.nodalExternalForces = nodalExternalForces;
|
||||
jobCopy.nodalForcedDisplacements = nodalForcedDisplacements;
|
||||
|
||||
return jobCopy;
|
||||
}
|
||||
std::string getLabel() const { return label; }
|
||||
|
||||
std::string toString() const {
|
||||
nlohmann::json json;
|
||||
if (!constrainedVertices.empty()) {
|
||||
json[jsonLabels.constrainedVertices] = constrainedVertices;
|
||||
}
|
||||
if (!nodalExternalForces.empty()) {
|
||||
std::unordered_map<VertexIndex, std::array<double, 6>> arrForces;
|
||||
for (const auto &f : nodalExternalForces) {
|
||||
arrForces[f.first] = f.second;
|
||||
}
|
||||
json[jsonLabels.nodalForces] = arrForces;
|
||||
}
|
||||
|
||||
return json.dump();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
label = "empty_job";
|
||||
constrainedVertices.clear();
|
||||
nodalExternalForces.clear();
|
||||
nodalForcedDisplacements.clear();
|
||||
if (pMesh.use_count() == 1) {
|
||||
std::cout << "Job mesh is deleted" << std::endl;
|
||||
}
|
||||
pMesh.reset();
|
||||
}
|
||||
|
||||
bool load(const std::string &jsonFilename, const bool &shouldLoadMesh = true)
|
||||
{
|
||||
label = "empty_job";
|
||||
constrainedVertices.clear();
|
||||
nodalExternalForces.clear();
|
||||
nodalForcedDisplacements.clear();
|
||||
const bool beVerbose = false;
|
||||
if (std::filesystem::path(jsonFilename).extension() != ".json") {
|
||||
std::cerr << "A json file is expected as input. The given file has the "
|
||||
"following extension:"
|
||||
<< std::filesystem::path(jsonFilename).extension() << std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(std::filesystem::path(jsonFilename))) {
|
||||
std::cerr << "The json file does not exist. Json file provided:" << jsonFilename
|
||||
<< std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (beVerbose) {
|
||||
std::cout << "Loading json file:" << jsonFilename << std::endl;
|
||||
}
|
||||
nlohmann::json json;
|
||||
std::ifstream ifs(jsonFilename);
|
||||
ifs >> json;
|
||||
|
||||
if (shouldLoadMesh) {
|
||||
pMesh.reset();
|
||||
pMesh = std::make_shared<SimulationMesh>();
|
||||
if (json.contains(jsonLabels.meshFilename)) {
|
||||
const std::string relativeFilepath = json[jsonLabels.meshFilename];
|
||||
const auto meshFilepath = std::filesystem::path(
|
||||
std::filesystem::path(jsonFilename).parent_path())
|
||||
.append(relativeFilepath);
|
||||
pMesh->load(meshFilepath.string());
|
||||
pMesh->setLabel(json[jsonLabels.meshLabel]); // FIXME: This should be exported using
|
||||
// nanoply but nanoply might not be able
|
||||
// to write a string(??)
|
||||
}
|
||||
|
||||
if (json.contains(jsonLabels.meshLabel)) {
|
||||
pMesh->setLabel(json[jsonLabels.meshLabel]);
|
||||
}
|
||||
}
|
||||
|
||||
if (json.contains(jsonLabels.constrainedVertices)) {
|
||||
constrainedVertices =
|
||||
// auto conV =
|
||||
json[jsonLabels.constrainedVertices]
|
||||
.get<std::unordered_map<VertexIndex, std::unordered_set<int>>>();
|
||||
if (beVerbose) {
|
||||
std::cout << "Loaded constrained vertices. Number of constrained "
|
||||
"vertices found:"
|
||||
<< constrainedVertices.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (json.contains(jsonLabels.nodalForces)) {
|
||||
auto f =
|
||||
json[jsonLabels.nodalForces].get<std::unordered_map<VertexIndex, std::array<double, 6>>>();
|
||||
for (const auto &force : f) {
|
||||
nodalExternalForces[force.first] = Vector6d(force.second);
|
||||
}
|
||||
if (beVerbose) {
|
||||
std::cout << "Loaded forces. Number of forces found:" << nodalExternalForces.size()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (json.contains(jsonLabels.forcedDisplacements)) {
|
||||
// auto conV =
|
||||
std::unordered_map<VertexIndex, std::array<double, 3>> forcedDisp
|
||||
= json[jsonLabels.forcedDisplacements]
|
||||
.get<std::unordered_map<VertexIndex, std::array<double, 3>>>();
|
||||
|
||||
for (const auto &fd : forcedDisp) {
|
||||
nodalForcedDisplacements[fd.first] = Eigen::Vector3d(fd.second[0],
|
||||
fd.second[1],
|
||||
fd.second[2]);
|
||||
}
|
||||
if (beVerbose) {
|
||||
std::cout << "Loaded forced displacements. Number of forced displaced"
|
||||
"vertices found:"
|
||||
<< nodalForcedDisplacements.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (json.contains(jsonLabels.label)) {
|
||||
label = json[jsonLabels.label];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool save(const std::string &folderDirectory) const
|
||||
{
|
||||
const std::filesystem::path pathFolderDirectory(folderDirectory);
|
||||
if (!std::filesystem::is_directory(pathFolderDirectory)) {
|
||||
std::cerr << "A folder directory is expected for saving the simulation "
|
||||
"job. Exiting.."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool returnValue = true;
|
||||
std::string jsonFilename(
|
||||
std::filesystem::path(pathFolderDirectory)
|
||||
// .append(label + "_" + pMesh->getLabel() + "_simulationJob.json")
|
||||
.append("SimulationJob.json")
|
||||
.string());
|
||||
|
||||
const std::string meshFilename = std::filesystem::absolute(
|
||||
std::filesystem::canonical(
|
||||
std::filesystem::path(pathFolderDirectory)))
|
||||
.append(pMesh->getLabel() + ".ply")
|
||||
.string();
|
||||
returnValue = pMesh->save(meshFilename);
|
||||
nlohmann::json json;
|
||||
json[jsonLabels.meshFilename]= std::filesystem::relative(std::filesystem::path(meshFilename),std::filesystem::path(jsonFilename).parent_path()).string();
|
||||
json[jsonLabels.meshLabel]
|
||||
= pMesh->getLabel(); // FIXME: This should be exported using nanoply but
|
||||
// nanoply might not be able to write a string(??)
|
||||
if (!constrainedVertices.empty()) {
|
||||
json[jsonLabels.constrainedVertices] = constrainedVertices;
|
||||
}
|
||||
if (!nodalExternalForces.empty()) {
|
||||
std::unordered_map<VertexIndex, std::array<double, 6>> arrForces;
|
||||
for (const auto &f : nodalExternalForces) {
|
||||
arrForces[f.first] = f.second;
|
||||
}
|
||||
json[jsonLabels.nodalForces] = arrForces;
|
||||
}
|
||||
if (!nodalForcedDisplacements.empty()) {
|
||||
std::unordered_map<VertexIndex, std::array<double, 3>> forcedDisp;
|
||||
for (const auto &fd : nodalForcedDisplacements) {
|
||||
forcedDisp[fd.first] = {fd.second[0], fd.second[1], fd.second[2]};
|
||||
}
|
||||
|
||||
json[jsonLabels.forcedDisplacements] = forcedDisp;
|
||||
}
|
||||
|
||||
if (!label.empty()) {
|
||||
json[jsonLabels.label] = label;
|
||||
}
|
||||
if (!pMesh->getLabel().empty()) {
|
||||
json[jsonLabels.meshLabel] = pMesh->getLabel();
|
||||
}
|
||||
std::ofstream jsonFile(jsonFilename);
|
||||
jsonFile << json;
|
||||
jsonFile.close();
|
||||
// std::cout << "Saved simulation job as:" << jsonFilename << std::endl;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
void registerForDrawing(const std::string &meshLabel, const bool &shouldEnable = false) const
|
||||
{
|
||||
PolyscopeInterface::init();
|
||||
if (meshLabel.empty()) {
|
||||
assert(false);
|
||||
std::cerr << "Expects a mesh label on which to draw the simulation job." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!polyscope::hasCurveNetwork(meshLabel)) {
|
||||
assert(false);
|
||||
std::cerr << "Expects mesh already being registered to draw the "
|
||||
"simulation job. No struct named "
|
||||
+ meshLabel
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
std::vector<std::array<double, 3>> nodeColors(pMesh->VN());
|
||||
for (const auto &fixedVertex : constrainedVertices) {
|
||||
const bool hasRotationalDoFConstrained = fixedVertex.second.contains(3)
|
||||
|| fixedVertex.second.contains(4)
|
||||
|| fixedVertex.second.contains(5);
|
||||
const bool hasTranslationalDoFConstrained = fixedVertex.second.contains(0)
|
||||
|| fixedVertex.second.contains(1)
|
||||
|| fixedVertex.second.contains(2);
|
||||
if (hasTranslationalDoFConstrained && !hasRotationalDoFConstrained) {
|
||||
nodeColors[fixedVertex.first] = {0, 0, 1};
|
||||
} else if (!hasTranslationalDoFConstrained && hasRotationalDoFConstrained) {
|
||||
nodeColors[fixedVertex.first] = {0, 1, 0};
|
||||
} else {
|
||||
nodeColors[fixedVertex.first] = {0, 1, 1};
|
||||
}
|
||||
}
|
||||
if (!nodalForcedDisplacements.empty()) {
|
||||
for (const std::pair<VertexIndex, Eigen::Vector3d> &viDisplPair :
|
||||
nodalForcedDisplacements) {
|
||||
const VertexIndex vi = viDisplPair.first;
|
||||
nodeColors[vi][0] += 1;
|
||||
nodeColors[vi][0] /= 2;
|
||||
nodeColors[vi][1] += 0;
|
||||
nodeColors[vi][1] /= 2;
|
||||
nodeColors[vi][2] += 0;
|
||||
nodeColors[vi][2] /= 2;
|
||||
}
|
||||
}
|
||||
std::for_each(nodeColors.begin(), nodeColors.end(), [](std::array<double, 3> &color) {
|
||||
const double norm = sqrt(std::pow(color[0], 2) + std::pow(color[1], 2)
|
||||
+ std::pow(color[2], 2));
|
||||
if (norm > std::pow(10, -7)) {
|
||||
color[0] /= norm;
|
||||
color[1] /= norm;
|
||||
color[2] /= norm;
|
||||
}
|
||||
});
|
||||
|
||||
// if (!nodeColors.empty()) {
|
||||
// polyscope::getCurveNetwork(meshLabel)
|
||||
// ->addNodeColorQuantity("Boundary conditions_" + label, nodeColors)
|
||||
// ->setEnabled(shouldEnable);
|
||||
// }
|
||||
|
||||
// per node external forces
|
||||
std::vector<std::array<double, 3>> externalForces(pMesh->VN());
|
||||
for (const auto &forcePair : nodalExternalForces) {
|
||||
auto index = forcePair.first;
|
||||
auto force = forcePair.second;
|
||||
externalForces[index] = {force[0], force[1], force[2]};
|
||||
}
|
||||
|
||||
if (!externalForces.empty()) {
|
||||
polyscope::CurveNetworkNodeVectorQuantity *externalForcesVectors
|
||||
= polyscope::getCurveNetwork(meshLabel)->addNodeVectorQuantity("External force_"
|
||||
+ label,
|
||||
externalForces);
|
||||
|
||||
const std::array<double, 3> color_loads{1.0, 0, 0};
|
||||
externalForcesVectors->setVectorColor(
|
||||
glm::vec3(color_loads[0], color_loads[1], color_loads[2]));
|
||||
externalForcesVectors->setEnabled(shouldEnable);
|
||||
}
|
||||
// per node external moments
|
||||
bool hasExternalMoments = false;
|
||||
std::vector<std::array<double, 3>> externalMoments(pMesh->VN());
|
||||
for (const auto &forcePair : nodalExternalForces) {
|
||||
auto index = forcePair.first;
|
||||
const Vector6d &load = forcePair.second;
|
||||
if (load.getRotation().norm() != 0) {
|
||||
hasExternalMoments = true;
|
||||
}
|
||||
externalMoments[index] = {load[3], load[4], load[5]};
|
||||
}
|
||||
|
||||
if (hasExternalMoments) {
|
||||
polyscope::getCurveNetwork(meshLabel)
|
||||
->addNodeVectorQuantity("External moment_" + label, externalMoments)
|
||||
->setEnabled(shouldEnable);
|
||||
}
|
||||
}
|
||||
void unregister(const std::string &meshLabel)
|
||||
{
|
||||
if (polyscope::getCurveNetwork(meshLabel) == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!nodalExternalForces.empty()) {
|
||||
polyscope::getCurveNetwork(meshLabel)->removeQuantity("External force_" + label);
|
||||
}
|
||||
if (!constrainedVertices.empty()) {
|
||||
polyscope::getCurveNetwork(meshLabel)->removeQuantity("Boundary conditions_" + label);
|
||||
}
|
||||
|
||||
// per node external moments
|
||||
bool hasExternalMoments = false;
|
||||
for (const auto &forcePair : nodalExternalForces) {
|
||||
const Vector6d &load = forcePair.second;
|
||||
if (load.getRotation().norm() != 0) {
|
||||
hasExternalMoments = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasExternalMoments) {
|
||||
polyscope::getCurveNetwork(meshLabel)->removeQuantity("External moment_" + label);
|
||||
}
|
||||
}
|
||||
#endif // POLYSCOPE_DEFINED
|
||||
};
|
||||
struct SimulationResults
|
||||
{
|
||||
/*TODO: remove rotationalDisplacementQuaternion since the last three components of the displacments
|
||||
* vector contains the same info using euler angles
|
||||
*/
|
||||
inline const static std::string defaultJsonFilename{"SimulationResults.json"};
|
||||
bool converged{false};
|
||||
std::shared_ptr<SimulationJob> pJob;
|
||||
SimulationHistory history;
|
||||
std::vector<Vector6d> debug_drmDisplacements;
|
||||
std::vector<Eigen::Quaternion<double>> debug_q_f1; //per vertex
|
||||
std::vector<Eigen::Quaternion<double>> debug_q_normal; //per vertex
|
||||
std::vector<Eigen::Quaternion<double>> debug_q_nr; //per vertex
|
||||
std::vector<Vector6d> displacements;
|
||||
std::vector<Eigen::Quaternion<double>> rotationalDisplacementQuaternion; //per vertex
|
||||
double internalPotentialEnergy{0};
|
||||
double executionTime{0};
|
||||
std::string labelPrefix{"deformed"};
|
||||
inline static char deliminator{' '};
|
||||
SimulationResults() { pJob = std::make_shared<SimulationJob>(); }
|
||||
|
||||
std::vector<VectorType> getTranslationalDisplacements() const
|
||||
{
|
||||
std::vector<VectorType> translationalDisplacements(displacements.size());
|
||||
std::transform(displacements.begin(),
|
||||
displacements.end(),
|
||||
translationalDisplacements.begin(),
|
||||
[&](const Vector6d &d) { return VectorType(d[0], d[1], d[2]); });
|
||||
|
||||
return translationalDisplacements;
|
||||
}
|
||||
|
||||
void setLabelPrefix(const std::string &lp) { labelPrefix += deliminator + lp; }
|
||||
std::string getLabel() const
|
||||
{
|
||||
return labelPrefix + deliminator + pJob->pMesh->getLabel() + deliminator + pJob->getLabel();
|
||||
}
|
||||
|
||||
bool saveDeformedModel(const std::string &outputFolder = std::string())
|
||||
{
|
||||
VCGEdgeMesh m;
|
||||
vcg::tri::Append<VCGEdgeMesh, SimulationMesh>::MeshCopy(m, *pJob->pMesh);
|
||||
|
||||
for (int vi = 0; vi < m.VN(); vi++) {
|
||||
m.vert[vi].P() = m.vert[vi].P()
|
||||
+ CoordType(displacements[vi][0],
|
||||
displacements[vi][1],
|
||||
displacements[vi][2]);
|
||||
}
|
||||
return m.save(std::filesystem::path(outputFolder).append(getLabel() + ".ply").string());
|
||||
}
|
||||
|
||||
void save(const std::string &outputFolder = std::string())
|
||||
{
|
||||
const std::filesystem::path outputFolderPath = outputFolder.empty()
|
||||
? std::filesystem::current_path()
|
||||
: std::filesystem::path(outputFolder);
|
||||
// std::cout << "Saving results to:" << outputFolderPath << std::endl;
|
||||
std::filesystem::path simulationJobOutputFolderPath
|
||||
= std::filesystem::path(outputFolderPath).append("SimulationJob");
|
||||
std::filesystem::create_directories(simulationJobOutputFolderPath);
|
||||
pJob->save(simulationJobOutputFolderPath.string());
|
||||
const std::string filename(getLabel() + "_displacements.eigenBin");
|
||||
|
||||
Eigen::MatrixXd m = Utilities::toEigenMatrix(displacements);
|
||||
const std::filesystem::path resultsFolderPath(
|
||||
std::filesystem::path(outputFolder).append("Results"));
|
||||
std::filesystem::create_directories(resultsFolderPath);
|
||||
Eigen::write_binary(std::filesystem::path(resultsFolderPath).append(filename).string(), m);
|
||||
|
||||
nlohmann::json json;
|
||||
|
||||
json[GET_VARIABLE_NAME(internalPotentialEnergy)] = internalPotentialEnergy;
|
||||
|
||||
std::filesystem::path jsonFilePath(
|
||||
std::filesystem::path(resultsFolderPath).append(defaultJsonFilename));
|
||||
std::ofstream jsonFile(jsonFilePath.string());
|
||||
jsonFile << json;
|
||||
jsonFile.close();
|
||||
|
||||
saveDeformedModel(resultsFolderPath.string());
|
||||
}
|
||||
|
||||
// The comparison of the results happens comparing the 6-dof nodal
|
||||
// displacements
|
||||
bool isEqual(const Eigen::MatrixXd &nodalDisplacements, double &error)
|
||||
{
|
||||
assert(nodalDisplacements.cols() == 6);
|
||||
Eigen::MatrixXd eigenDisplacements = Utilities::toEigenMatrix(this->displacements);
|
||||
const double errorNorm = (eigenDisplacements - nodalDisplacements).norm();
|
||||
error = errorNorm;
|
||||
return errorNorm < 1e-10;
|
||||
// return eigenDisplacements.isApprox(nodalDisplacements);
|
||||
}
|
||||
|
||||
void load(const std::filesystem::path &loadFromPath, const std::filesystem::path &loadJobFrom)
|
||||
{
|
||||
pJob->load(std::filesystem::path(loadJobFrom).append("SimulationJob.json").string());
|
||||
load(loadFromPath);
|
||||
}
|
||||
void load(const std::filesystem::path &loadFromPath, const std::shared_ptr<SimulationJob> &pJob)
|
||||
{
|
||||
this->pJob = pJob;
|
||||
load(loadFromPath);
|
||||
}
|
||||
static double computeDistance(
|
||||
const SimulationResults &resultsA,
|
||||
const SimulationResults &resultsB,
|
||||
const std::unordered_map<VertexIndex, VertexIndex> &resultsAToResultsBViMap)
|
||||
{
|
||||
double distance = 0;
|
||||
for (std::pair<int, int> resultsAToResultsBViPair : resultsAToResultsBViMap) {
|
||||
const double vertexToVertexDistance
|
||||
= (resultsA.displacements[resultsAToResultsBViPair.first].getTranslation()
|
||||
- resultsB.displacements[resultsAToResultsBViPair.second].getTranslation())
|
||||
.norm();
|
||||
distance += vertexToVertexDistance;
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
double computeDistance(const SimulationResults &other,
|
||||
const std::unordered_map<VertexIndex, VertexIndex> &thisToOtherViMap) const
|
||||
{
|
||||
return computeDistance(*this, other, thisToOtherViMap);
|
||||
}
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
void unregister() const
|
||||
{
|
||||
if (!polyscope::hasCurveNetwork(getLabel())) {
|
||||
std::cerr << "No curve network registered with a name: " << getLabel() << std::endl;
|
||||
std::cerr << "Nothing to remove." << std::endl;
|
||||
return;
|
||||
}
|
||||
pJob->unregister(getLabel());
|
||||
polyscope::removeCurveNetwork(getLabel());
|
||||
}
|
||||
polyscope::CurveNetwork *registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor = std::nullopt,
|
||||
const bool &shouldEnable = true,
|
||||
const double &desiredRadius = 0.001,
|
||||
// const double &desiredRadius = 0.0001,
|
||||
const bool &shouldShowFrames = false) const
|
||||
{
|
||||
PolyscopeInterface::init();
|
||||
const std::shared_ptr<SimulationMesh> &mesh = pJob->pMesh;
|
||||
polyscope::CurveNetwork *polyscopeHandle_deformedEdmeMesh;
|
||||
if (!polyscope::hasStructure(getLabel())) {
|
||||
const auto verts = mesh->getEigenVertices();
|
||||
const auto edges = mesh->getEigenEdges();
|
||||
polyscopeHandle_deformedEdmeMesh = polyscope::registerCurveNetwork(getLabel(),
|
||||
verts,
|
||||
edges);
|
||||
} else {
|
||||
polyscopeHandle_deformedEdmeMesh = polyscope::getCurveNetwork(getLabel());
|
||||
}
|
||||
polyscopeHandle_deformedEdmeMesh->setEnabled(shouldEnable);
|
||||
polyscopeHandle_deformedEdmeMesh->setRadius(desiredRadius, true);
|
||||
if (desiredColor.has_value()) {
|
||||
const glm::vec3 desiredColor_glm(desiredColor.value()[0],
|
||||
desiredColor.value()[1],
|
||||
desiredColor.value()[2]);
|
||||
polyscopeHandle_deformedEdmeMesh->setColor(desiredColor_glm);
|
||||
}
|
||||
Eigen::MatrixX3d nodalDisplacements(mesh->VN(), 3);
|
||||
Eigen::MatrixX3d framesX(mesh->VN(), 3);
|
||||
Eigen::MatrixX3d framesY(mesh->VN(), 3);
|
||||
Eigen::MatrixX3d framesZ(mesh->VN(), 3);
|
||||
|
||||
Eigen::MatrixX3d framesX_initial(mesh->VN(), 3);
|
||||
Eigen::MatrixX3d framesY_initial(mesh->VN(), 3);
|
||||
Eigen::MatrixX3d framesZ_initial(mesh->VN(), 3);
|
||||
|
||||
// std::unordered_set<int> interfaceNodes{1, 3, 5, 7, 9, 11};
|
||||
// std::unordered_set<int> interfaceNodes{3, 7, 11, 15, 19, 23};
|
||||
// std::unordered_set<int> interfaceNodes{};
|
||||
for (VertexIndex vi = 0; vi < mesh->VN(); vi++) {
|
||||
const Vector6d &nodalDisplacement = displacements[vi];
|
||||
nodalDisplacements.row(vi) = Eigen::Vector3d(nodalDisplacement[0],
|
||||
nodalDisplacement[1],
|
||||
nodalDisplacement[2]);
|
||||
// Eigen::Quaternion<double> Rx(Eigen::AngleAxis(nodalDisplacement[2],Eigen::Vector3d(1, 0, 0)));
|
||||
// Eigen::Quaternion<double> Ry(Eigen::AngleAxis(nodalDisplacement[4],Eigen::Vector3d(0, 1, 0)));
|
||||
// Eigen::Quaternion<double> Rz(Eigen::AngleAxis(nodalDisplacement[5],Eigen::Vector3d(0, 0, 1)));
|
||||
// Eigen::Quaternion<double> R=Rx*Ry*Rz;
|
||||
// if (interfaceNodes.contains(vi)) {
|
||||
auto deformedNormal = rotationalDisplacementQuaternion[vi] * Eigen::Vector3d(0, 0, 1);
|
||||
auto deformedFrameY = rotationalDisplacementQuaternion[vi] * Eigen::Vector3d(0, 1, 0);
|
||||
auto deformedFrameX = rotationalDisplacementQuaternion[vi] * Eigen::Vector3d(1, 0, 0);
|
||||
framesX.row(vi) = Eigen::Vector3d(deformedFrameX[0],
|
||||
deformedFrameX[1],
|
||||
deformedFrameX[2]);
|
||||
framesY.row(vi) = Eigen::Vector3d(deformedFrameY[0],
|
||||
deformedFrameY[1],
|
||||
deformedFrameY[2]);
|
||||
framesZ.row(vi) = Eigen::Vector3d(deformedNormal[0],
|
||||
deformedNormal[1],
|
||||
deformedNormal[2]);
|
||||
framesX_initial.row(vi) = Eigen::Vector3d(1, 0, 0);
|
||||
framesY_initial.row(vi) = Eigen::Vector3d(0, 1, 0);
|
||||
framesZ_initial.row(vi) = Eigen::Vector3d(0, 0, 1);
|
||||
// } else {
|
||||
// framesX.row(vi) = Eigen::Vector3d(0, 0, 0);
|
||||
// framesY.row(vi) = Eigen::Vector3d(0, 0, 0);
|
||||
// framesZ.row(vi) = Eigen::Vector3d(0, 0, 0);
|
||||
// framesX_initial.row(vi) = Eigen::Vector3d(0, 0, 0);
|
||||
// framesY_initial.row(vi) = Eigen::Vector3d(0, 0, 0);
|
||||
// framesZ_initial.row(vi) = Eigen::Vector3d(0, 0, 0);
|
||||
// }
|
||||
}
|
||||
polyscopeHandle_deformedEdmeMesh->updateNodePositions(mesh->getEigenVertices()
|
||||
+ nodalDisplacements);
|
||||
|
||||
const double frameRadius_default = 0.035;
|
||||
const double frameLength_default = 0.035;
|
||||
const bool shouldEnable_default = true;
|
||||
//if(showFramesOn.contains(vi)){
|
||||
auto polyscopeHandle_frameX = polyscopeHandle_deformedEdmeMesh
|
||||
->addNodeVectorQuantity("FrameX", framesX);
|
||||
polyscopeHandle_frameX->setVectorLengthScale(frameLength_default);
|
||||
polyscopeHandle_frameX->setVectorRadius(frameRadius_default);
|
||||
polyscopeHandle_frameX->setVectorColor(
|
||||
/*polyscope::getNextUniqueColor()*/ glm::vec3(1, 0, 0));
|
||||
auto polyscopeHandle_frameY = polyscopeHandle_deformedEdmeMesh
|
||||
->addNodeVectorQuantity("FrameY", framesY);
|
||||
polyscopeHandle_frameY->setVectorLengthScale(frameLength_default);
|
||||
polyscopeHandle_frameY->setVectorRadius(frameRadius_default);
|
||||
polyscopeHandle_frameY->setVectorColor(
|
||||
/*polyscope::getNextUniqueColor()*/ glm::vec3(0, 1, 0));
|
||||
auto polyscopeHandle_frameZ = polyscopeHandle_deformedEdmeMesh
|
||||
->addNodeVectorQuantity("FrameZ", framesZ);
|
||||
polyscopeHandle_frameZ->setVectorLengthScale(frameLength_default);
|
||||
polyscopeHandle_frameZ->setVectorRadius(frameRadius_default);
|
||||
polyscopeHandle_frameZ->setVectorColor(
|
||||
/*polyscope::getNextUniqueColor()*/ glm::vec3(0, 0, 1));
|
||||
|
||||
auto polyscopeHandle_initialMesh = polyscope::getCurveNetwork(mesh->getLabel());
|
||||
if (!polyscopeHandle_initialMesh) {
|
||||
polyscopeHandle_initialMesh = mesh->registerForDrawing();
|
||||
}
|
||||
|
||||
// auto polyscopeHandle_frameX_initial = polyscopeHandle_initialMesh
|
||||
// ->addNodeVectorQuantity("FrameX", framesX_initial);
|
||||
// polyscopeHandle_frameX_initial->setVectorLengthScale(frameLength_default);
|
||||
// polyscopeHandle_frameX_initial->setVectorRadius(frameRadius_default);
|
||||
// polyscopeHandle_frameX_initial->setVectorColor(
|
||||
// /*polyscope::getNextUniqueColor()*/ glm::vec3(1, 0, 0));
|
||||
// auto polyscopeHandle_frameY_initial = polyscopeHandle_initialMesh
|
||||
// ->addNodeVectorQuantity("FrameY", framesY_initial);
|
||||
// polyscopeHandle_frameY_initial->setVectorLengthScale(frameLength_default);
|
||||
// polyscopeHandle_frameY_initial->setVectorRadius(frameRadius_default);
|
||||
// polyscopeHandle_frameY_initial->setVectorColor(
|
||||
// /*polyscope::getNextUniqueColor()*/ glm::vec3(0, 1, 0));
|
||||
// auto polyscopeHandle_frameZ_initial = polyscopeHandle_initialMesh
|
||||
// ->addNodeVectorQuantity("FrameZ", framesZ_initial);
|
||||
// polyscopeHandle_frameZ_initial->setVectorLengthScale(frameLength_default);
|
||||
// polyscopeHandle_frameZ_initial->setVectorRadius(frameRadius_default);
|
||||
// polyscopeHandle_frameZ_initial->setVectorColor(
|
||||
// /*polyscope::getNextUniqueColor()*/ glm::vec3(0, 0, 1));
|
||||
// //}
|
||||
pJob->registerForDrawing(getLabel());
|
||||
// static bool wasExecuted =false;
|
||||
// if (!wasExecuted) {
|
||||
// std::function<void()> callback = [&]() {
|
||||
// static bool showFrames = shouldShowFrames;
|
||||
|
||||
// if (ImGui::Checkbox("Show Frames", &showFrames) && showFrames) {
|
||||
// polyscopeHandle_frameX->setEnabled(showFrames);
|
||||
// polyscopeHandle_frameY->setEnabled(showFrames);
|
||||
// polyscopeHandle_frameZ->setEnabled(showFrames);
|
||||
// }
|
||||
// };
|
||||
|
||||
// PolyscopeInterface::addUserCallback(callback);
|
||||
// wasExecuted = true;
|
||||
// }
|
||||
return polyscopeHandle_deformedEdmeMesh;
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
bool load(const std::filesystem::path &loadFromPath)
|
||||
{
|
||||
converged = true; //assuming it has converged
|
||||
assert(pJob != nullptr);
|
||||
//load job
|
||||
//Use the first .eigenBin file for loading the displacements
|
||||
for (auto const &entry : std::filesystem::recursive_directory_iterator(loadFromPath)) {
|
||||
if (std::filesystem::is_regular_file(entry) && entry.path().extension() == ".eigenBin") {
|
||||
Eigen::MatrixXd displacements_eigen;
|
||||
Eigen::read_binary(entry.path().string(), displacements_eigen);
|
||||
displacements = Utilities::fromEigenMatrix(displacements_eigen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rotationalDisplacementQuaternion.resize(pJob->pMesh->VN());
|
||||
for (int vi = 0; vi < pJob->pMesh->VN(); vi++) {
|
||||
rotationalDisplacementQuaternion[vi] = Eigen::AngleAxisd(displacements[vi][3],
|
||||
Eigen::Vector3d::UnitX())
|
||||
* Eigen::AngleAxisd(displacements[vi][4],
|
||||
Eigen::Vector3d::UnitY())
|
||||
* Eigen::AngleAxisd(displacements[vi][5],
|
||||
Eigen::Vector3d::UnitZ());
|
||||
}
|
||||
|
||||
const std::filesystem::path jsonFilepath = std::filesystem::path(loadFromPath)
|
||||
.append(defaultJsonFilename);
|
||||
if (!std::filesystem::exists(jsonFilepath)) {
|
||||
std::cerr << "Simulation results could not be loaded because filepath does "
|
||||
"not exist:"
|
||||
<< jsonFilepath << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::ifstream ifs(jsonFilepath);
|
||||
nlohmann::json json;
|
||||
ifs >> json;
|
||||
if (json.contains(GET_VARIABLE_NAME(internalPotentialEnergy))) {
|
||||
internalPotentialEnergy = json.at(GET_VARIABLE_NAME(internalPotentialEnergy));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SIMULATIONHISTORY_HPP
|
|
@ -0,0 +1,193 @@
|
|||
#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> &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);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
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.sumOfNormalizedDisplacementNorms.empty()) {
|
||||
createPlot("Number of Iterations",
|
||||
"Sum of normalized displacement norms",
|
||||
history.sumOfNormalizedDisplacementNorms,
|
||||
std::filesystem::path(graphsFolder)
|
||||
.append("SumOfNormalizedDisplacementNorms_" + graphSuffix + ".png")
|
||||
.string(),
|
||||
history.redMarks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SIMULATIONHISTORYPLOTTER_HPP
|
|
@ -0,0 +1,511 @@
|
|||
#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) {
|
||||
getEdges(eigenEdges);
|
||||
// }
|
||||
// eigenVertices = triMesh.getEigenVertices();
|
||||
// if (eigenVertices.rows() == 0) {
|
||||
getVertices(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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
#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 previousTotalKineticEnergy{0};
|
||||
double previousTotalResidualForcesNorm{0};
|
||||
double currentTotalKineticEnergy{0};
|
||||
double currentTotalTranslationalKineticEnergy{0};
|
||||
double totalResidualForcesNorm{0};
|
||||
double totalExternalForcesNorm{0};
|
||||
double averageResidualForcesNorm{0};
|
||||
double currentTotalPotentialEnergykN{0};
|
||||
double previousTotalPotentialEnergykN{0};
|
||||
double residualForcesMovingAverageDerivativeNorm{0};
|
||||
double residualForcesMovingAverage{0};
|
||||
double sumOfNormalizedDisplacementNorms{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();
|
||||
};
|
||||
|
||||
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 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 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
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef SIMULATIONMODEL_HPP
|
||||
#define SIMULATIONMODEL_HPP
|
||||
|
||||
#include "simulation_structs.hpp"
|
||||
|
||||
class SimulationModel
|
||||
{
|
||||
public:
|
||||
virtual SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &simulationJob)
|
||||
= 0;
|
||||
};
|
||||
|
||||
#endif // SIMULATIONMODEL_HPP
|
|
@ -1,25 +0,0 @@
|
|||
#include "simulationmodelfactory.hpp"
|
||||
|
||||
SimulationModelFactory::SimulationModelFactory() {}
|
||||
|
||||
std::unique_ptr<SimulationModel> SimulationModelFactory::create(
|
||||
const std::string& simulationModelLabel) {
|
||||
if (simulationModelLabel == DRMSimulationModel::label) {
|
||||
return std::make_unique<DRMSimulationModel>();
|
||||
} else if (simulationModelLabel == ChronosEulerSimulationModel::label) {
|
||||
return std::make_unique<ChronosEulerSimulationModel>();
|
||||
} else if (simulationModelLabel == ChronosEulerLinearSimulationModel::label) {
|
||||
return std::make_unique<ChronosEulerLinearSimulationModel>();
|
||||
} else if (simulationModelLabel ==
|
||||
ChronosEulerNonLinearSimulationModel::label) {
|
||||
return std::make_unique<ChronosEulerNonLinearSimulationModel>();
|
||||
} else if (simulationModelLabel == LinearSimulationModel::label) {
|
||||
return std::make_unique<LinearSimulationModel>();
|
||||
}
|
||||
std::cerr
|
||||
<< "Simulation model used for computing the optimization results was "
|
||||
"not recognized"
|
||||
<< std::endl;
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef SIMULATIONMODELFACTORY_HPP
|
||||
#define SIMULATIONMODELFACTORY_HPP
|
||||
|
||||
#include "chronoseulerlinearsimulationmodel.hpp"
|
||||
#include "chronoseulernonlinearsimulationmodel.hpp"
|
||||
#include "chronoseulersimulationmodel.hpp"
|
||||
#include "der_leimer.hpp"
|
||||
#include "drmsimulationmodel.hpp"
|
||||
#include "linearsimulationmodel.hpp"
|
||||
#include <string>
|
||||
|
||||
class SimulationModelFactory {
|
||||
public:
|
||||
SimulationModelFactory();
|
||||
static std::unique_ptr<SimulationModel>
|
||||
create(const std::string &simulationModelLabel);
|
||||
};
|
||||
|
||||
#endif // SIMULATIONMODELFACTORY_HPP
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,73 +1,70 @@
|
|||
#ifndef FLATPATTERNGEOMETRY_HPP
|
||||
#define FLATPATTERNGEOMETRY_HPP
|
||||
#include "edgemesh.hpp"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "edgemesh.hpp"
|
||||
#include "polymesh.hpp"
|
||||
#include "vcgtrimesh.hpp"
|
||||
#include "polymesh.hpp"
|
||||
|
||||
class PatternGeometry;
|
||||
using ConstPatternGeometry = PatternGeometry;
|
||||
|
||||
class PatternGeometry : public VCGEdgeMesh {
|
||||
private:
|
||||
size_t computeTiledValence(
|
||||
const size_t& nodeIndex,
|
||||
const std::vector<size_t>& numberOfNodesPerSlot) const;
|
||||
size_t getNodeValence(const size_t& nodeIndex) const;
|
||||
size_t getNodeSlot(const size_t& nodeIndex) const;
|
||||
class PatternGeometry : public VCGEdgeMesh
|
||||
{
|
||||
private:
|
||||
size_t
|
||||
computeTiledValence(const size_t &nodeIndex,
|
||||
const std::vector<size_t> &numberOfNodesPerSlot) const;
|
||||
size_t getNodeValence(const size_t &nodeIndex) const;
|
||||
size_t getNodeSlot(const size_t &nodeIndex) const;
|
||||
|
||||
void addNormals();
|
||||
double baseTriangleHeight;
|
||||
double computeBaseTriangleHeight() const;
|
||||
|
||||
inline static size_t fanSize{6};
|
||||
std::vector<VCGEdgeMesh::CoordType> vertices;
|
||||
const double triangleEdgeSize{1}; // radius edge
|
||||
const double triangleEdgeSize{1}; // radius edge
|
||||
std::unordered_map<size_t, size_t> nodeToSlotMap;
|
||||
std::unordered_map<size_t, size_t> correspondingNode;
|
||||
std::unordered_map<size_t, size_t> nodeTiledValence;
|
||||
vcg::Triangle3<double> baseTriangle;
|
||||
|
||||
void constructCorrespondingNodeMap(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot);
|
||||
void
|
||||
constructCorrespondingNodeMap(const std::vector<size_t> &numberOfNodesPerSlot);
|
||||
|
||||
void constructNodeToTiledValenceMap(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot);
|
||||
void constructNodeToTiledValenceMap(const std::vector<size_t> &numberOfNodesPerSlot);
|
||||
|
||||
std::vector<VectorType> getEdgeVectorsWithVertexAsOrigin(
|
||||
std::vector<EdgePointer>& edgePointers,
|
||||
const int& vi);
|
||||
std::vector<VectorType> getEdgeVectorsWithVertexAsOrigin(std::vector<EdgePointer> &edgePointers,
|
||||
const int &vi);
|
||||
|
||||
public:
|
||||
inline static VectorType DefaultNormal{0.0, 0.0, 1.0};
|
||||
public:
|
||||
PatternGeometry();
|
||||
/*The following function should be a copy constructor with
|
||||
* a const argument but this is impossible due to the
|
||||
* vcglib interface.
|
||||
* */
|
||||
PatternGeometry(PatternGeometry& other);
|
||||
bool load(const std::filesystem::path& meshFilePath) override;
|
||||
void add(const std::vector<vcg::Point3d>& vertices);
|
||||
void add(const std::vector<vcg::Point2i>& edges);
|
||||
void add(const std::vector<vcg::Point3d>& vertices,
|
||||
const std::vector<vcg::Point2i>& edges);
|
||||
void add(const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const std::vector<vcg::Point2i>& edges);
|
||||
static std::vector<vcg::Point3d> constructVertexVector(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const size_t& fanSize,
|
||||
const double& triangleEdgeSize);
|
||||
bool hasDanglingEdges(const std::vector<size_t>& numberOfNodesPerSlot);
|
||||
bool hasValenceGreaterThan(const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const size_t& valenceThreshold);
|
||||
std::vector<vcg::Point3d> computeVertices() const;
|
||||
static PatternGeometry createFan(PatternGeometry& pattern);
|
||||
static PatternGeometry createTile(PatternGeometry& pattern);
|
||||
PatternGeometry(PatternGeometry &other);
|
||||
bool load(const std::filesystem::path &meshFilePath) override;
|
||||
void add(const std::vector<vcg::Point3d> &vertices);
|
||||
void add(const std::vector<vcg::Point2i> &edges);
|
||||
void add(const std::vector<vcg::Point3d> &vertices, const std::vector<vcg::Point2i> &edges);
|
||||
void add(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
const std::vector<vcg::Point2i> &edges);
|
||||
static std::vector<vcg::Point3d>
|
||||
constructVertexVector(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
const size_t &fanSize, const double &triangleEdgeSize);
|
||||
bool hasDanglingEdges(const std::vector<size_t> &numberOfNodesPerSlot);
|
||||
bool hasValenceGreaterThan(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
const size_t &valenceThreshold);
|
||||
std::vector<vcg::Point3d> getVertices() const;
|
||||
static PatternGeometry createFan(PatternGeometry &pattern);
|
||||
static PatternGeometry createTile(PatternGeometry &pattern);
|
||||
double getTriangleEdgeSize() const;
|
||||
bool hasUntiledDanglingEdges();
|
||||
std::unordered_map<size_t, std::unordered_set<size_t>> getIntersectingEdges(
|
||||
size_t& numberOfIntersectingEdgePairs) const;
|
||||
std::unordered_map<size_t, std::unordered_set<size_t>>
|
||||
getIntersectingEdges(size_t &numberOfIntersectingEdgePairs) const;
|
||||
|
||||
static size_t binomialCoefficient(size_t n, size_t m) {
|
||||
assert(n >= m);
|
||||
|
@ -76,73 +73,60 @@ class PatternGeometry : public VCGEdgeMesh {
|
|||
bool isFullyConnectedWhenFanned();
|
||||
|
||||
bool hasIntersectingEdges(
|
||||
const std::string& patternBinaryRepresentation,
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>&
|
||||
intersectingEdges);
|
||||
const std::string &patternBinaryRepresentation,
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>
|
||||
&intersectingEdges);
|
||||
bool isPatternValid();
|
||||
size_t getFanSize() const;
|
||||
void add(const std::vector<vcg::Point2d>& vertices,
|
||||
const std::vector<vcg::Point2i>& edges);
|
||||
void add(const std::vector<vcg::Point2d> &vertices,
|
||||
const std::vector<vcg::Point2i> &edges);
|
||||
|
||||
PatternGeometry(const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const std::vector<vcg::Point2i>& edges);
|
||||
PatternGeometry(const std::filesystem::path& patternFilePath,
|
||||
bool addNormalsIfAbsent = true);
|
||||
PatternGeometry(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
const std::vector<vcg::Point2i> &edges);
|
||||
PatternGeometry(const std::string &filename, bool addNormalsIfAbsent = true);
|
||||
|
||||
bool createHoneycombAtom();
|
||||
void copy(PatternGeometry& copyFrom);
|
||||
void copy(PatternGeometry ©From);
|
||||
|
||||
void tilePattern(VCGEdgeMesh& pattern,
|
||||
VCGPolyMesh& tileInto,
|
||||
const int& interfaceNodeIndex,
|
||||
const bool& shouldDeleteDanglingEdges);
|
||||
void tilePattern(VCGEdgeMesh &pattern,
|
||||
VCGPolyMesh &tileInto,
|
||||
const int &interfaceNodeIndex,
|
||||
const bool &shouldDeleteDanglingEdges);
|
||||
|
||||
void scale(const double& desiredBaseTriangleCentralEdgeSize);
|
||||
void scale(const double &desiredBaseTriangleCentralEdgeSize, const int &interfaceNodeIndex);
|
||||
|
||||
double getBaseTriangleHeight() const;
|
||||
vcg::Triangle3<double> computeBaseTriangle() const;
|
||||
void updateBaseTriangle();
|
||||
double computeBaseTriangleHeight() const;
|
||||
void updateBaseTriangleHeight();
|
||||
|
||||
// PatternGeometry(const std::vector<vcg::Point2d> &vertices, const
|
||||
// std::vector<vcg::Point2i> &edges); static std::shared_ptr<PatternGeometry>
|
||||
// tilePattern(
|
||||
PatternGeometry(const std::vector<vcg::Point2d> &vertices, const std::vector<vcg::Point2i> &edges);
|
||||
// static std::shared_ptr<PatternGeometry> tilePattern(
|
||||
// std::vector<PatternGeometry> &pattern,
|
||||
// const std::vector<int> &connectToNeighborsVi,
|
||||
// const VCGPolyMesh &tileInto,
|
||||
// std::vector<int> &tileIntoEdgesToTiledVi,
|
||||
// std::vector<std::vector<size_t>> &perPatternEdges);
|
||||
virtual void createFan(/*const std::vector<int> &connectToNeighborsVi =
|
||||
std::vector<int>(),*/
|
||||
const size_t& fanSize = 6);
|
||||
int interfaceNodeIndex{
|
||||
3}; // TODO: Fix this. This should be automatically computed
|
||||
bool hasAngleSmallerThanThreshold(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const double& angleThreshold_degrees,
|
||||
const bool shouldBreak = false);
|
||||
void createFan(const std::vector<int> &connectToNeighborsVi = std::vector<int>(),
|
||||
const size_t &fanSize = 6);
|
||||
int interfaceNodeIndex{3}; //TODO: Fix this. This should be automatically computed
|
||||
bool hasAngleSmallerThanThreshold(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
const double &angleThreshold_degrees);
|
||||
vcg::Triangle3<double> getBaseTriangle() const;
|
||||
static std::shared_ptr<PatternGeometry> tilePattern(PatternGeometry &pattern,
|
||||
const std::vector<int> &connectToNeighborsVi,
|
||||
const VCGPolyMesh &tileInto,
|
||||
std::vector<int> &tileIntoEdgesToTiledVi);
|
||||
static std::shared_ptr<PatternGeometry> tilePattern(
|
||||
PatternGeometry& pattern,
|
||||
const std::vector<int>& connectToNeighborsVi,
|
||||
const VCGPolyMesh& tileInto,
|
||||
std::vector<int>& tileIntoEdgesToTiledVi);
|
||||
static std::shared_ptr<PatternGeometry> tilePattern(
|
||||
std::vector<ConstPatternGeometry>& patterns,
|
||||
const std::vector<int>& connectToNeighborsVi,
|
||||
const VCGPolyMesh& tileInto,
|
||||
const std::vector<int>& perSurfaceFacePatternIndices,
|
||||
std::vector<size_t>& tileIntoEdgesToTiledVi,
|
||||
std::vector<std::vector<size_t>>& perPatternIndexTiledPatternEdgeIndex);
|
||||
std::unordered_set<VertexIndex> getInterfaceNodes(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot);
|
||||
bool isInterfaceConnected(
|
||||
const std::unordered_set<VertexIndex>& interfaceNodes);
|
||||
std::vector<ConstPatternGeometry> &patterns,
|
||||
const std::vector<int> &connectToNeighborsVi,
|
||||
const VCGPolyMesh &tileInto,
|
||||
const std::vector<int> &perSurfaceFacePatternIndices,
|
||||
std::vector<size_t> &tileIntoEdgesToTiledVi,
|
||||
std::vector<std::vector<size_t>> &perPatternIndexTiledPatternEdgeIndex);
|
||||
std::unordered_set<VertexIndex> getInterfaceNodes(const std::vector<size_t> &numberOfNodesPerSlot);
|
||||
bool isInterfaceConnected(const std::unordered_set<VertexIndex> &interfaceNodes);
|
||||
void deleteDanglingVertices() override;
|
||||
void deleteDanglingVertices(
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer>& pu)
|
||||
override;
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> &pu) override;
|
||||
};
|
||||
|
||||
#endif // FLATPATTERNGEOMETRY_HPP
|
||||
#endif // FLATPATTERNGEOMETRY_HPP
|
||||
|
|
|
@ -0,0 +1,472 @@
|
|||
#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>
|
||||
|
||||
#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 {
|
||||
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)
|
||||
{
|
||||
for (const std::filesystem::directory_entry &dirEntry :
|
||||
std::filesystem::directory_iterator(folderPath)) {
|
||||
if (dirEntry.is_regular_file() && std::filesystem::path(dirEntry).extension() == extension) {
|
||||
return std::filesystem::path(dirEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace Utilities
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include "polyscope/curve_network.h"
|
||||
#include "polyscope/pick.h"
|
||||
#include "polyscope/polyscope.h"
|
||||
#include <functional>
|
||||
|
||||
namespace PolyscopeInterface {
|
||||
inline struct GlobalPolyscopeData
|
||||
{
|
||||
std::vector<std::function<void()>> userCallbacks;
|
||||
} globalPolyscopeData;
|
||||
|
||||
inline void mainCallback()
|
||||
{
|
||||
ImGui::PushItemWidth(100); // Make ui elements 100 pixels wide,
|
||||
// instead of full width. Must have
|
||||
// matching PopItemWidth() below.
|
||||
|
||||
for (std::function<void()> &userCallback : globalPolyscopeData.userCallbacks) {
|
||||
userCallback();
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
inline void addUserCallback(const std::function<void()> &userCallback)
|
||||
{
|
||||
globalPolyscopeData.userCallbacks.push_back(userCallback);
|
||||
}
|
||||
|
||||
inline void deinitPolyscope()
|
||||
{
|
||||
if (!polyscope::state::initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
polyscope::render::engine->shutdownImGui();
|
||||
}
|
||||
|
||||
inline void init()
|
||||
{
|
||||
if (polyscope::state::initialized) {
|
||||
return;
|
||||
}
|
||||
polyscope::init();
|
||||
polyscope::options::groundPlaneEnabled = false;
|
||||
polyscope::view::upDir = polyscope::view::UpDir::ZUp;
|
||||
|
||||
polyscope::state::userCallback = &mainCallback;
|
||||
polyscope::options::autocenterStructures = false;
|
||||
polyscope::options::autoscaleStructures = false;
|
||||
}
|
||||
using PolyscopeLabel = std::string;
|
||||
inline std::pair<PolyscopeLabel, size_t> 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);
|
||||
}
|
||||
|
||||
inline void registerWorldAxes()
|
||||
{
|
||||
PolyscopeInterface::init();
|
||||
|
||||
Eigen::MatrixX3d axesPositions(4, 3);
|
||||
axesPositions.row(0) = Eigen::Vector3d(0, 0, 0);
|
||||
// axesPositions.row(1) = Eigen::Vector3d(polyscope::state::lengthScale, 0, 0);
|
||||
// axesPositions.row(2) = Eigen::Vector3d(0, polyscope::state::lengthScale, 0);
|
||||
// axesPositions.row(3) = Eigen::Vector3d(0, 0, polyscope::state::lengthScale);
|
||||
axesPositions.row(1) = Eigen::Vector3d(1, 0, 0);
|
||||
axesPositions.row(2) = Eigen::Vector3d(0, 1, 0);
|
||||
axesPositions.row(3) = Eigen::Vector3d(0, 0, 1);
|
||||
|
||||
Eigen::MatrixX2i axesEdges(3, 2);
|
||||
axesEdges.row(0) = Eigen::Vector2i(0, 1);
|
||||
axesEdges.row(1) = Eigen::Vector2i(0, 2);
|
||||
axesEdges.row(2) = Eigen::Vector2i(0, 3);
|
||||
Eigen::MatrixX3d axesColors(3, 3);
|
||||
axesColors.row(0) = Eigen::Vector3d(1, 0, 0);
|
||||
axesColors.row(1) = Eigen::Vector3d(0, 1, 0);
|
||||
axesColors.row(2) = Eigen::Vector3d(0, 0, 1);
|
||||
|
||||
const std::string worldAxesName = "World Axes";
|
||||
polyscope::registerCurveNetwork(worldAxesName, axesPositions, axesEdges);
|
||||
polyscope::getCurveNetwork(worldAxesName)->setRadius(0.0001, false);
|
||||
const std::string worldAxesColorName = worldAxesName + " Color";
|
||||
polyscope::getCurveNetwork(worldAxesName)
|
||||
->addEdgeColorQuantity(worldAxesColorName, axesColors)
|
||||
->setEnabled(true);
|
||||
}
|
||||
} // namespace PolyscopeInterface
|
||||
|
||||
#endif
|
||||
|
||||
// namespace ConfigurationFile {
|
||||
|
||||
//}
|
||||
//} // namespace ConfigurationFile
|
||||
template <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>
|
||||
std::string to_string_with_precision(const T a_value, const int n = 2)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out.precision(n);
|
||||
out << std::fixed << a_value;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
template<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
|
|
@ -6,9 +6,6 @@
|
|||
#include <wrap/io_trimesh/export.h>
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
//#include <wrap/nanoply/include/nanoplyWrapper.hpp>
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include <polyscope/curve_network.h>
|
||||
#endif
|
||||
|
||||
bool VCGTriMesh::load(const std::filesystem::__cxx11::path &meshFilePath) {
|
||||
assert(std::filesystem::exists(meshFilePath));
|
||||
|
@ -39,32 +36,6 @@ bool VCGTriMesh::load(const std::filesystem::__cxx11::path &meshFilePath) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VCGTriMesh::load(std::istringstream &offInputStream)
|
||||
{
|
||||
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;
|
||||
const bool openingFromStreamErrorCode
|
||||
= vcg::tri::io::ImporterOFF<VCGTriMesh>::OpenStream(*this, offInputStream, mask);
|
||||
if (openingFromStreamErrorCode != 0) {
|
||||
std::cerr << "Error reading from stream:"
|
||||
<< vcg::tri::io::ImporterOFF<VCGTriMesh>::ErrorMsg(openingFromStreamErrorCode)
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
vcg::tri::UpdateTopology<VCGTriMesh>::AllocateEdge(*this);
|
||||
vcg::tri::UpdateTopology<VCGTriMesh>::FaceFace(*this);
|
||||
vcg::tri::UpdateTopology<VCGTriMesh>::VertexFace(*this);
|
||||
vcg::tri::UpdateTopology<VCGTriMesh>::VertexEdge(*this);
|
||||
vcg::tri::UpdateNormal<VCGTriMesh>::PerVertexNormalized(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Eigen::MatrixX3d VCGTriMesh::getVertices() const
|
||||
{
|
||||
// vcg::tri::Allocator<VCGTriMesh>::CompactVertexVector(m);
|
||||
|
@ -121,7 +92,8 @@ bool VCGTriMesh::save(const std::string plyFilename)
|
|||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
|
||||
polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing(const std::optional<std::array<float, 3> > &desiredColor, const bool &shouldEnable) const
|
||||
polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor, const bool &shouldEnable) const
|
||||
{
|
||||
auto vertices = getVertices();
|
||||
auto faces = getFaces();
|
||||
|
@ -145,7 +117,7 @@ polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing(const std::optional<std::
|
|||
const glm::vec3 desiredColor_glm(desiredColor.value()[0],
|
||||
desiredColor.value()[1],
|
||||
desiredColor.value()[2]);
|
||||
polyscopeHandle_mesh->setSurfaceColor(desiredColor_glm);
|
||||
polyscopeHandle_mesh->setSurfaceColor(glm::normalize(desiredColor_glm));
|
||||
}
|
||||
return polyscopeHandle_mesh;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef VCGTRIMESH_HPP
|
||||
#define VCGTRIMESH_HPP
|
||||
#include "mesh.hpp"
|
||||
#include <vcg/complex/complex.h>
|
||||
#include <optional>
|
||||
#include "mesh.hpp"
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
#include <polyscope/surface_mesh.h>
|
||||
|
@ -22,42 +22,39 @@ class VCGTriMeshVertex : public vcg::Vertex<VCGTriMeshUsedTypes,
|
|||
vcg::vertex::Color4b,
|
||||
vcg::vertex::VFAdj,
|
||||
vcg::vertex::Qualityd,
|
||||
vcg::vertex::VEAdj> {};
|
||||
class VCGTriMeshFace : public vcg::Face<VCGTriMeshUsedTypes,
|
||||
vcg::face::FFAdj,
|
||||
vcg::face::VFAdj,
|
||||
vcg::face::VertexRef,
|
||||
vcg::face::BitFlags,
|
||||
vcg::face::Normal3d> {};
|
||||
class VCGTriMeshEdge : public vcg::Edge<VCGTriMeshUsedTypes,
|
||||
vcg::edge::VertexRef,
|
||||
vcg::edge::VEAdj> {};
|
||||
vcg::vertex::VEAdj>
|
||||
{};
|
||||
class VCGTriMeshFace
|
||||
: public vcg::Face<VCGTriMeshUsedTypes, vcg::face::FFAdj, vcg::face::VFAdj,
|
||||
vcg::face::VertexRef, vcg::face::BitFlags,
|
||||
vcg::face::Normal3d> {};
|
||||
class VCGTriMeshEdge : public vcg::Edge<VCGTriMeshUsedTypes, vcg::edge::VertexRef, vcg::edge::VEAdj>
|
||||
{};
|
||||
|
||||
class VCGTriMesh : public vcg::tri::TriMesh<std::vector<VCGTriMeshVertex>,
|
||||
std::vector<VCGTriMeshFace>,
|
||||
std::vector<VCGTriMeshEdge>>,
|
||||
public Mesh {
|
||||
public:
|
||||
public Mesh
|
||||
{
|
||||
public:
|
||||
VCGTriMesh();
|
||||
VCGTriMesh(const std::string& filename);
|
||||
bool load(const std::filesystem::path& meshFilePath) override;
|
||||
bool load(std::istringstream& offInputStream);
|
||||
VCGTriMesh(const std::string &filename);
|
||||
bool load(const std::filesystem::path &meshFilePath) override;
|
||||
Eigen::MatrixX3d getVertices() const;
|
||||
Eigen::MatrixX3i getFaces() const;
|
||||
bool save(const std::string plyFilename);
|
||||
template <typename MeshElement>
|
||||
size_t getIndex(const MeshElement& element) {
|
||||
template <typename MeshElement> size_t getIndex(const MeshElement &element) {
|
||||
return vcg::tri::Index<VCGTriMesh>(*this, element);
|
||||
}
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
polyscope::SurfaceMesh* registerForDrawing(
|
||||
const std::optional<std::array<float, 3>>& desiredColor = std::nullopt,
|
||||
const bool& shouldEnable = true) const;
|
||||
polyscope::SurfaceMesh *registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor = std::nullopt,
|
||||
const bool &shouldEnable = true) const;
|
||||
#endif
|
||||
Eigen::MatrixX2i getEdges() const;
|
||||
void updateEigenEdgeAndVertices();
|
||||
void moveToCenter();
|
||||
};
|
||||
|
||||
#endif // VCGTRIMESH_HPP
|
||||
#endif // VCGTRIMESH_HPP
|
||||
|
|
Loading…
Reference in New Issue