Compare commits
72 Commits
master
...
reducedOpt
Author | SHA1 | Date |
---|---|---|
iasonmanolas | 3c664856ef | |
iasonmanolas | 76433eaa9d | |
iasonmanolas | db8aa4124e | |
iasonmanolas | 6e08bc039b | |
iasonmanolas | 158db04660 | |
iasonmanolas | 266aca08c2 | |
iasonmanolas | 01dff95f9d | |
iasonmanolas | dd21445f52 | |
iasonmanolas | 68d5655214 | |
iasonmanolas | 9fd536ccf3 | |
iasonmanolas | 7780e4ab38 | |
iasonmanolas | 90551e5485 | |
iasonmanolas | 76fb1b8609 | |
iasonmanolas | 164f156aa7 | |
iasonmanolas | 382ef273a4 | |
iasonmanolas | 6762c266c0 | |
iasonmanolas | 3092809d02 | |
iasonmanolas | d8a6fadab7 | |
iasonmanolas | 7a0124155c | |
iasonmanolas | ef18646cfd | |
iasonmanolas | 96e63d15a3 | |
iasonmanolas | 8f80c654b2 | |
iasonmanolas | cb1d6b811d | |
iasonmanolas | bed30a2bc4 | |
iasonmanolas | 395bf92486 | |
iasonmanolas | ba52c4215e | |
iasonmanolas | 0d07f1c831 | |
iasonmanolas | b4fb31748c | |
iasonmanolas | a0ed388c56 | |
iasonmanolas | 2c462d9ebf | |
iasonmanolas | 50045330ae | |
iasonmanolas | db35df38fc | |
iasonmanolas | fd5e9755ab | |
iasonmanolas | b4928c720b | |
iasonmanolas | adaf49627f | |
iasonmanolas | e70b4e9863 | |
iasonmanolas | 9d9f7dbacf | |
iasonmanolas | 8a335411d9 | |
iasonmanolas | c3802cfc87 | |
iasonmanolas | d02587c1b8 | |
iasonmanolas | 27548bd7b0 | |
iasonmanolas | 897bb4400a | |
iasonmanolas | 54da8ac343 | |
iasonmanolas | 3e5dc29bc1 | |
iasonmanolas | b2bd12d8df | |
iasonmanolas | 90dc2ac081 | |
iasonmanolas | 7f11ea8a47 | |
iasonmanolas | f531b16b19 | |
iasonmanolas | 398df24056 | |
iasonmanolas | 0cb175e72e | |
iasonmanolas | a7fdf431dd | |
iasonmanolas | e9707e2cfb | |
iasonmanolas | 436ece0d88 | |
iasonmanolas | 3d0de46922 | |
iasonmanolas | 96807c3b85 | |
iasonmanolas | 5c4f8c0bd5 | |
iasonmanolas | 45eed0e3da | |
iasonmanolas | bef2ae8860 | |
iasonmanolas | ec7160e637 | |
iasonmanolas | 6c16d8d48e | |
iasonmanolas | 5f863af7ce | |
iasonmanolas | e1f66515d5 | |
iasonmanolas | 9e121beade | |
iasonmanolas | 33facf05ab | |
iasonmanolas | e54dc0a27c | |
iasonmanolas | 7f543ef21a | |
iasonmanolas | 366727ced6 | |
iasonmanolas | 068626f299 | |
iasonmanolas | c513abc45b | |
iasonmanolas | 8e33ba35aa | |
iasonmanolas | 38c2535a34 | |
iasonmanolas | 643e8b35be |
261
CMakeLists.txt
261
CMakeLists.txt
|
@ -1,12 +1,13 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(MySources)
|
||||
|
||||
file(GLOB MySourcesFiles ${CMAKE_CURRENT_LIST_DIR}/*.hpp ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
|
||||
add_library(${PROJECT_NAME} ${MySourcesFiles} )
|
||||
add_library(${PROJECT_NAME} STATIC ${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()
|
||||
|
@ -18,93 +19,141 @@ if(NOT EXISTS ${EXTERNAL_DEPS_DIR})
|
|||
endif()
|
||||
##Create directory for the external libraries
|
||||
file(MAKE_DIRECTORY ${EXTERNAL_DEPS_DIR})
|
||||
if(${USE_POLYSCOPE})
|
||||
set(POLYSCOPE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/polyscope)
|
||||
download_project(PROJ POLYSCOPE
|
||||
GIT_REPOSITORY https://github.com/nmwsharp/polyscope.git
|
||||
|
||||
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
|
||||
GIT_TAG master
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
BINARY_DIR ${POLYSCOPE_BINARY_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${POLYSCOPE_SOURCE_DIR} ${POLYSCOPE_BINARY_DIR})
|
||||
add_compile_definitions(POLYSCOPE_DEFINED)
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${POLYSCOPE_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.cpp)
|
||||
FetchContent_MakeAvailable(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)
|
||||
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
|
||||
download_project(PROJ vcglib_devel
|
||||
FetchContent_Declare(vcglib
|
||||
GIT_REPOSITORY https://gitea-s2i2s.isti.cnr.it/manolas/vcglib.git
|
||||
GIT_TAG devel
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${vcglib_devel_SOURCE_DIR} ${vcglib_devel_BINARY_DIR})
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${vcglib_devel_SOURCE_DIR}/wrap/ply/plylib.cpp)
|
||||
FetchContent_MakeAvailable(vcglib)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${vcglib_SOURCE_DIR})
|
||||
target_sources(${PROJECT_NAME} PUBLIC ${vcglib_SOURCE_DIR}/wrap/ply/plylib.cpp)
|
||||
|
||||
##matplot++ lib
|
||||
set(MATPLOTPLUSPLUS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/matplot)
|
||||
download_project(PROJ MATPLOTPLUSPLUS
|
||||
###matplot++ lib
|
||||
FetchContent_Declare(matplot
|
||||
GIT_REPOSITORY https://github.com/alandefreitas/matplotplusplus
|
||||
GIT_TAG master
|
||||
BINARY_DIR ${MATPLOTPLUSPLUS_BINARY_DIR}
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${MATPLOTPLUSPLUS_SOURCE_DIR} ${MATPLOTPLUSPLUS_BINARY_DIR})
|
||||
FetchContent_MakeAvailable(matplot)
|
||||
|
||||
##threed-beam-fea
|
||||
set(threed-beam-fea_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/threed-beam-fea)
|
||||
download_project(PROJ threed-beam-fea
|
||||
GIT_REPOSITORY https://github.com/IasonManolas/threed-beam-fea.git
|
||||
if(NOT TARGET ThreedBeamFEA)
|
||||
FetchContent_Declare(threed-beam-fea
|
||||
GIT_REPOSITORY https://gitea-s2i2s.isti.cnr.it/manolas/threed-beam-fea.git
|
||||
GIT_TAG master
|
||||
BINARY_DIR ${threed-beam-fea_BINARY_DIR}
|
||||
PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
)
|
||||
add_subdirectory(${threed-beam-fea_SOURCE_DIR} ${threed-beam-fea_BINARY_DIR})
|
||||
FetchContent_MakeAvailable(threed-beam-fea)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ThreedBeamFEA)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${threed-beam-fea_SOURCE_DIR})
|
||||
|
||||
##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)
|
||||
#set(threed-beam-fea_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/threed-beam-fea)
|
||||
#download_project(PROJ threed-beam-fea
|
||||
## GIT_REPOSITORY https://github.com/IasonManolas/threed-beam-fea.git
|
||||
# GIT_TAG master
|
||||
# BINARY_DIR ${threed-beam-fea_BINARY_DIR}
|
||||
# PREFIX ${EXTERNAL_DEPS_DIR}
|
||||
# ${UPDATE_DISCONNECTED_IF_AVAILABLE}
|
||||
#)
|
||||
#add_subdirectory(${threed-beam-fea_SOURCE_DIR} ${threed-beam-fea_BINARY_DIR})
|
||||
|
||||
find_package(Eigen3 3.4 REQUIRED)
|
||||
if(MSVC)
|
||||
add_compile_definitions(_HAS_STD_BYTE=0)
|
||||
endif(MSVC)
|
||||
#link_directories(${CMAKE_CURRENT_LIST_DIR}/boost_graph/libs)
|
||||
|
||||
if(${MYSOURCES_STATIC_LINK})
|
||||
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)
|
||||
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)
|
||||
else()
|
||||
# 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()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen tbb pthread matplot)
|
||||
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 ThreedBeamFEA
|
||||
PUBLIC matplot
|
||||
)
|
||||
|
||||
if(USE_ENSMALLEN)
|
||||
##ENSMALLEN
|
||||
|
||||
#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
|
||||
|
@ -113,13 +162,93 @@ if(USE_ENSMALLEN)
|
|||
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)
|
||||
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)
|
||||
endif()
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${ARMADILLO_SOURCE_DIR}/include ${ENSMALLEN_SOURCE_DIR})
|
||||
|
||||
##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)
|
||||
|
|
|
@ -1,355 +0,0 @@
|
|||
<?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>
|
80
beam.hpp
80
beam.hpp
|
@ -1,80 +0,0 @@
|
|||
#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
|
|
@ -0,0 +1,13 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#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
|
|
@ -0,0 +1,13 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#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
|
|
@ -0,0 +1,307 @@
|
|||
#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);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#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
|
|
@ -0,0 +1,300 @@
|
|||
#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() {}
|
|
@ -0,0 +1,39 @@
|
|||
#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
|
67
csvfile.hpp
67
csvfile.hpp
|
@ -9,12 +9,12 @@
|
|||
#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_;
|
||||
|
@ -22,11 +22,14 @@ class csvFile {
|
|||
const std::string special_chars_;
|
||||
|
||||
public:
|
||||
csvFile(const std::filesystem::path &filename,
|
||||
CSVFile(const std::filesystem::path& filename,
|
||||
const bool& overwrite,
|
||||
const std::string separator = ",")
|
||||
: fs_(), is_first_(true), separator_(separator), escape_seq_("\""), special_chars_("\"")
|
||||
{
|
||||
: 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);
|
||||
|
@ -37,11 +40,12 @@ class csvFile {
|
|||
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();
|
||||
}
|
||||
|
@ -53,24 +57,23 @@ 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)
|
||||
{
|
||||
CSVFile& operator<<(const T& val) {
|
||||
return write(val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::vector<std::vector<T>> parse(const std::filesystem::path &csvFilepath)
|
||||
{
|
||||
std::vector<std::vector<T>> resultCSV;
|
||||
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;
|
||||
std::cerr << "The file does not exist:" << csvFilepath.string()
|
||||
<< std::endl;
|
||||
return resultCSV;
|
||||
}
|
||||
|
||||
|
@ -79,21 +82,18 @@ class csvFile {
|
|||
std::cerr << "Can't open file:" << csvFilepath.string() << std::endl;
|
||||
return resultCSV;
|
||||
}
|
||||
std::vector<T> row;
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,8 @@ class csvFile {
|
|||
}
|
||||
|
||||
private:
|
||||
template <typename T> csvFile &write(const T &val) {
|
||||
template <typename T>
|
||||
CSVFile& write(const T& val) {
|
||||
if (!is_first_) {
|
||||
fs_ << separator_;
|
||||
} else {
|
||||
|
@ -125,12 +126,12 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,193 @@
|
|||
#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
|
@ -1,295 +0,0 @@
|
|||
#ifndef BEAMFORMFINDER_HPP
|
||||
#define BEAMFORMFINDER_HPP
|
||||
|
||||
//#ifdef USE_MATPLOT
|
||||
//#include "matplot.h"
|
||||
#include <matplot/matplot.h>
|
||||
//#endif
|
||||
#include "simulationmesh.hpp"
|
||||
#include "simulationmodel.hpp"
|
||||
#include <Eigen/Dense>
|
||||
#include <filesystem>
|
||||
#include <unordered_set>
|
||||
|
||||
#ifdef USE_ENSMALLEN
|
||||
#include <armadillo>
|
||||
#include <ensmallen.hpp>
|
||||
#endif
|
||||
|
||||
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-5};
|
||||
std::optional<int> maxDRMIterations;
|
||||
std::optional<int> debugModeStep;
|
||||
std::optional<double> totalTranslationalKineticEnergyThreshold;
|
||||
std::optional<double> averageResidualForcesCriterionThreshold;
|
||||
std::optional<double> linearGuessForceScaleFactor;
|
||||
// std::optional<int> intermediateResultsSaveStep;
|
||||
std::optional<bool> saveIntermediateBestStates;
|
||||
std::optional<double> viscousDampingFactor;
|
||||
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
|
495
edgemesh.cpp
495
edgemesh.cpp
|
@ -1,495 +0,0 @@
|
|||
#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
|
127
edgemesh.hpp
127
edgemesh.hpp
|
@ -1,127 +0,0 @@
|
|||
#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.
|
@ -7,7 +7,6 @@ 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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,374 @@
|
|||
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
|
|
@ -0,0 +1,69 @@
|
|||
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
|
|
@ -0,0 +1,26 @@
|
|||
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
|
|
@ -1,274 +0,0 @@
|
|||
#include "linearsimulationmodel.hpp"
|
||||
//#include "gsl/gsl"
|
||||
|
||||
std::vector<fea::Elem> LinearSimulationModel::getFeaElements(
|
||||
const std::shared_ptr<SimulationMesh> &pMesh)
|
||||
{
|
||||
const int numberOfEdges = pMesh->EN();
|
||||
std::vector<fea::Elem> elements(numberOfEdges);
|
||||
for (int edgeIndex = 0; edgeIndex < numberOfEdges; edgeIndex++) {
|
||||
const SimulationMesh::CoordType &evn0 = pMesh->edge[edgeIndex].cV(0)->cN();
|
||||
const SimulationMesh::CoordType &evn1 = pMesh->edge[edgeIndex].cV(1)->cN();
|
||||
const std::vector<double> nAverageVector{(evn0[0] + evn1[0]) / 2,
|
||||
(evn0[1] + evn1[1]) / 2,
|
||||
(evn0[2] + evn1[2]) / 2};
|
||||
const Element &element = pMesh->elements[edgeIndex];
|
||||
const double E = element.material.youngsModulus;
|
||||
fea::Props feaProperties(E * element.dimensions.A,
|
||||
E * element.dimensions.inertia.I3,
|
||||
E * element.dimensions.inertia.I2,
|
||||
element.material.G * element.dimensions.inertia.J,
|
||||
nAverageVector);
|
||||
const int vi0 = pMesh->getIndex(pMesh->edge[edgeIndex].cV(0));
|
||||
const int vi1 = pMesh->getIndex(pMesh->edge[edgeIndex].cV(1));
|
||||
elements[edgeIndex] = fea::Elem(vi0, vi1, feaProperties);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
std::vector<fea::Node> LinearSimulationModel::getFeaNodes(
|
||||
const std::shared_ptr<SimulationMesh> &pMesh)
|
||||
{
|
||||
const int numberOfNodes = pMesh->VN();
|
||||
std::vector<fea::Node> feaNodes(numberOfNodes);
|
||||
for (int vi = 0; vi < numberOfNodes; vi++) {
|
||||
const CoordType &p = pMesh->vert[vi].cP();
|
||||
feaNodes[vi] = fea::Node(p[0], p[1], p[2]);
|
||||
}
|
||||
|
||||
return feaNodes;
|
||||
}
|
||||
|
||||
std::vector<fea::BC> LinearSimulationModel::getFeaFixedNodes(
|
||||
const std::shared_ptr<SimulationJob> &job)
|
||||
{
|
||||
std::vector<fea::BC> boundaryConditions;
|
||||
// boundaryConditions.reserve(job->constrainedVertices.size() * 6
|
||||
// + job->nodalForcedDisplacements.size() * 3);
|
||||
for (auto fixedVertex : job->constrainedVertices) {
|
||||
const int vertexIndex = fixedVertex.first;
|
||||
for (int dofIndex : fixedVertex.second) {
|
||||
boundaryConditions.emplace_back(
|
||||
fea::BC(vertexIndex, static_cast<fea::DOF>(dofIndex), 0));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto forcedDisplacement : job->nodalForcedDisplacements) {
|
||||
const int vi = forcedDisplacement.first;
|
||||
for (int dofIndex = 0; dofIndex < 3; dofIndex++) {
|
||||
boundaryConditions.emplace_back(
|
||||
fea::BC(vi, static_cast<fea::DOF>(dofIndex), forcedDisplacement.second[dofIndex]));
|
||||
}
|
||||
}
|
||||
|
||||
return boundaryConditions;
|
||||
}
|
||||
|
||||
std::vector<fea::Force> LinearSimulationModel::getFeaNodalForces(
|
||||
const std::shared_ptr<SimulationJob> &job)
|
||||
{
|
||||
std::vector<fea::Force> nodalForces;
|
||||
nodalForces.reserve(job->nodalExternalForces.size() * 6);
|
||||
|
||||
for (auto nodalForce : job->nodalExternalForces) {
|
||||
for (int dofIndex = 0; dofIndex < 6; dofIndex++) {
|
||||
if (nodalForce.second[dofIndex] == 0) {
|
||||
continue;
|
||||
}
|
||||
fea::Force f(nodalForce.first, dofIndex, nodalForce.second[dofIndex]);
|
||||
nodalForces.emplace_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
return nodalForces;
|
||||
}
|
||||
|
||||
SimulationResults LinearSimulationModel::getResults(
|
||||
const fea::Summary &feaSummary, const std::shared_ptr<SimulationJob> &simulationJob)
|
||||
{
|
||||
SimulationResults results;
|
||||
results.converged = feaSummary.converged;
|
||||
if (!results.converged) {
|
||||
return results;
|
||||
}
|
||||
|
||||
results.executionTime = feaSummary.total_time_in_ms * 1000;
|
||||
// displacements
|
||||
results.displacements.resize(feaSummary.num_nodes);
|
||||
results.rotationalDisplacementQuaternion.resize(feaSummary.num_nodes);
|
||||
for (int vi = 0; vi < feaSummary.num_nodes; vi++) {
|
||||
results.displacements[vi] = Vector6d(feaSummary.nodal_displacements[vi]);
|
||||
|
||||
const Vector6d &nodalDisplacement = results.displacements[vi];
|
||||
Eigen::Quaternion<double> q_nx;
|
||||
q_nx = Eigen::AngleAxis<double>(nodalDisplacement[3], Eigen::Vector3d(1, 0, 0));
|
||||
Eigen::Quaternion<double> q_ny;
|
||||
q_ny = Eigen::AngleAxis<double>(nodalDisplacement[4], Eigen::Vector3d(0, 1, 0));
|
||||
Eigen::Quaternion<double> q_nz;
|
||||
q_nz = Eigen::AngleAxis<double>(nodalDisplacement[5], Eigen::Vector3d(0, 0, 1));
|
||||
results.rotationalDisplacementQuaternion[vi] = q_nx * q_ny * q_nz;
|
||||
}
|
||||
results.setLabelPrefix("Linear");
|
||||
|
||||
// // Convert forces
|
||||
// // Convert to vector of eigen matrices of the form force component-> per
|
||||
// // Edge
|
||||
// const int numDof = 6;
|
||||
// const size_t numberOfEdges = feaSummary.element_forces.size();
|
||||
// edgeForces =
|
||||
// std::vector<Eigen::VectorXd>(numDof, Eigen::VectorXd(2 *
|
||||
// numberOfEdges));
|
||||
// for (gsl::index edgeIndex = 0; edgeIndex < numberOfEdges; edgeIndex++) {
|
||||
// for (gsl::index forceComponentIndex = 0; forceComponentIndex < numDof;
|
||||
// forceComponentIndex++) {
|
||||
// (edgeForces[forceComponentIndex])(2 * edgeIndex) =
|
||||
// feaSummary.element_forces[edgeIndex][forceComponentIndex];
|
||||
// (edgeForces[forceComponentIndex])(2 * edgeIndex + 1) =
|
||||
// feaSummary.element_forces[edgeIndex][numDof +
|
||||
// forceComponentIndex];
|
||||
// }
|
||||
// }
|
||||
|
||||
for (int ei = 0; ei < feaSummary.num_elems; ei++) {
|
||||
const std::vector<double> &elementForces = feaSummary.element_forces[ei];
|
||||
const Element &element = simulationJob->pMesh->elements[ei];
|
||||
//Axial
|
||||
const double elementPotentialEnergy_axial_v0 = std::pow(elementForces[0], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.A);
|
||||
const double elementPotentialEnergy_axial_v1 = std::pow(elementForces[6], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.A);
|
||||
const double elementPotentialEnergy_axial = elementPotentialEnergy_axial_v0
|
||||
+ elementPotentialEnergy_axial_v1;
|
||||
//Shear
|
||||
const double elementPotentialEnergy_shearY_v0 = std::pow(elementForces[1], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shearZ_v0 = std::pow(elementForces[2], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shearY_v1 = std::pow(elementForces[7], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shearZ_v1 = std::pow(elementForces[8], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.A
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_shear = elementPotentialEnergy_shearY_v0
|
||||
+ elementPotentialEnergy_shearZ_v0
|
||||
+ elementPotentialEnergy_shearY_v1
|
||||
+ elementPotentialEnergy_shearZ_v1;
|
||||
//Bending
|
||||
const double elementPotentialEnergy_bendingY_v0 = std::pow(elementForces[4], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I2);
|
||||
const double elementPotentialEnergy_bendingZ_v0 = std::pow(elementForces[5], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I3);
|
||||
const double elementPotentialEnergy_bendingY_v1 = std::pow(elementForces[10], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I2);
|
||||
const double elementPotentialEnergy_bendingZ_v1 = std::pow(elementForces[11], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.material.youngsModulus
|
||||
* element.dimensions.inertia.I3);
|
||||
const double elementPotentialEnergy_bending = elementPotentialEnergy_bendingY_v0
|
||||
+ elementPotentialEnergy_bendingZ_v0
|
||||
+ elementPotentialEnergy_bendingY_v1
|
||||
+ elementPotentialEnergy_bendingZ_v1;
|
||||
//Torsion
|
||||
const double elementPotentialEnergy_torsion_v0 = std::pow(elementForces[3], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.inertia.J
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_torsion_v1 = std::pow(elementForces[9], 2)
|
||||
* element.initialLength
|
||||
/ (4 * element.dimensions.inertia.J
|
||||
* element.material.G);
|
||||
const double elementPotentialEnergy_torsion = elementPotentialEnergy_torsion_v0
|
||||
+ elementPotentialEnergy_torsion_v1;
|
||||
const double elementInternalPotentialEnergy = elementPotentialEnergy_axial
|
||||
+ elementPotentialEnergy_shear
|
||||
+ elementPotentialEnergy_bending
|
||||
+ elementPotentialEnergy_torsion;
|
||||
results.internalPotentialEnergy += elementInternalPotentialEnergy;
|
||||
}
|
||||
results.pJob = simulationJob;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
SimulationResults LinearSimulationModel::executeSimulation(
|
||||
const std::shared_ptr<SimulationJob> &pSimulationJob)
|
||||
{
|
||||
assert(pSimulationJob->pMesh->VN() != 0);
|
||||
const bool wasInitializedWithDifferentStructure = pSimulationJob->pMesh->EN()
|
||||
!= simulator.structure.elems.size()
|
||||
|| pSimulationJob->pMesh->VN()
|
||||
!= simulator.structure.nodes.size();
|
||||
if (!simulator.wasInitialized() || wasInitializedWithDifferentStructure) {
|
||||
setStructure(pSimulationJob->pMesh);
|
||||
}
|
||||
// printInfo(job);
|
||||
|
||||
// create the default options
|
||||
fea::Options opts;
|
||||
opts.save_elemental_forces = false;
|
||||
opts.save_nodal_displacements = false;
|
||||
opts.save_nodal_forces = false;
|
||||
opts.save_report = false;
|
||||
opts.save_tie_forces = false;
|
||||
// if (!elementalForcesOutputFilepath.empty()) {
|
||||
// opts.save_elemental_forces = true;
|
||||
// opts.elemental_forces_filename = elementalForcesOutputFilepath;
|
||||
// }
|
||||
// if (!nodalDisplacementsOutputFilepath.empty()) {
|
||||
// opts.save_nodal_displacements = true;
|
||||
// opts.nodal_displacements_filename = nodalDisplacementsOutputFilepath;
|
||||
// }
|
||||
|
||||
// have the program output status updates
|
||||
opts.verbose = false;
|
||||
|
||||
// form an empty vector of ties
|
||||
std::vector<fea::Tie> ties;
|
||||
|
||||
// also create an empty list of equations
|
||||
std::vector<fea::Equation> equations;
|
||||
auto fixedVertices = getFeaFixedNodes(pSimulationJob);
|
||||
auto nodalForces = getFeaNodalForces(pSimulationJob);
|
||||
fea::Summary feaResults = simulator.solve(fixedVertices, nodalForces, ties, equations, opts);
|
||||
|
||||
SimulationResults results = getResults(feaResults, pSimulationJob);
|
||||
results.pJob = pSimulationJob;
|
||||
return results;
|
||||
}
|
||||
|
||||
void LinearSimulationModel::setStructure(const std::shared_ptr<SimulationMesh> &pMesh)
|
||||
{
|
||||
fea::BeamStructure structure(getFeaNodes(pMesh), getFeaElements(pMesh));
|
||||
simulator.initialize(structure);
|
||||
}
|
||||
|
||||
void LinearSimulationModel::printInfo(const fea::BeamStructure &job)
|
||||
{
|
||||
std::cout << "Details regarding the fea::Job:" << std::endl;
|
||||
std::cout << "Nodes:" << std::endl;
|
||||
for (fea::Node n : job.nodes) {
|
||||
std::cout << n << std::endl;
|
||||
}
|
||||
std::cout << "Elements:" << std::endl;
|
||||
for (Eigen::Vector2i e : job.elems) {
|
||||
std::cout << e << std::endl;
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef LINEARSIMULATIONMODEL_HPP
|
||||
#define LINEARSIMULATIONMODEL_HPP
|
||||
|
||||
#include "simulationmodel.hpp"
|
||||
#include "threed_beam_fea.h"
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
class LinearSimulationModel : public SimulationModel
|
||||
{
|
||||
public:
|
||||
LinearSimulationModel(){
|
||||
|
||||
}
|
||||
static std::vector<fea::Elem> getFeaElements(const std::shared_ptr<SimulationMesh> &pMesh);
|
||||
|
||||
static std::vector<fea::Node> getFeaNodes(const std::shared_ptr<SimulationMesh> &pMesh);
|
||||
static std::vector<fea::BC> getFeaFixedNodes(const std::shared_ptr<SimulationJob> &job);
|
||||
|
||||
static std::vector<fea::Force> getFeaNodalForces(const std::shared_ptr<SimulationJob> &job);
|
||||
static SimulationResults getResults(const fea::Summary &feaSummary,
|
||||
const std::shared_ptr<SimulationJob> &simulationJob);
|
||||
|
||||
SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &simulationJob);
|
||||
void setStructure(const std::shared_ptr<SimulationMesh> &pMesh);
|
||||
|
||||
private:
|
||||
fea::ThreedBeamFEA simulator;
|
||||
static void printInfo(const fea::BeamStructure &job);
|
||||
};
|
||||
|
||||
#endif // LINEARSIMULATIONMODEL_HPP
|
31
mesh.hpp
31
mesh.hpp
|
@ -1,31 +0,0 @@
|
|||
#ifndef MESH_HPP
|
||||
#define MESH_HPP
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
class Mesh
|
||||
{
|
||||
protected:
|
||||
std::string label{"empty_label"};
|
||||
|
||||
public:
|
||||
virtual ~Mesh() = default;
|
||||
virtual bool load(const std::filesystem::path &meshFilePath) { return false; }
|
||||
virtual bool save(const std::filesystem::path &meshFilePath) { return false; }
|
||||
|
||||
std::string getLabel() const;
|
||||
void setLabel(const std::string &newLabel);
|
||||
void prependToLabel(const std::string &text);
|
||||
};
|
||||
|
||||
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
|
20719
nlohmann/json.hpp
20719
nlohmann/json.hpp
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,175 @@
|
|||
// __ _____ _____ _____
|
||||
// __| | __| | | | 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_
|
296
polymesh.hpp
296
polymesh.hpp
|
@ -1,296 +0,0 @@
|
|||
#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
|
|
@ -0,0 +1,94 @@
|
|||
#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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#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
|
|
@ -1,317 +1,694 @@
|
|||
#include "reducedmodelevaluator.hpp"
|
||||
#include "hexagonremesher.hpp"
|
||||
#include "trianglepatterngeometry.hpp"
|
||||
|
||||
#include <execution>
|
||||
#include <filesystem>
|
||||
|
||||
using FullPatternVertexIndex = VertexIndex;
|
||||
using ReducedPatternVertexIndex = VertexIndex;
|
||||
#include "hexagonremesher.hpp"
|
||||
#include "reducedmodel.hpp"
|
||||
#include "reducedmodeloptimizer.hpp"
|
||||
#include "simulationmodelfactory.hpp"
|
||||
#include "trianglepatterngeometry.hpp"
|
||||
|
||||
ReducedModelEvaluator::ReducedModelEvaluator()
|
||||
{
|
||||
using PatternVertexIndex = VertexIndex;
|
||||
using ReducedModelVertexIndex = VertexIndex;
|
||||
|
||||
}
|
||||
|
||||
std::vector<double> ReducedModelEvaluator::evaluateReducedModel(
|
||||
ReducedModelOptimization::Results &optimizationResults)
|
||||
{
|
||||
// std::shared_ptr<VCGPolyMesh> pTileIntoSurface = std::make_shared<VCGPolyMesh>();
|
||||
// std::filesystem::path tileIntoSurfaceFilePath{
|
||||
// "/home/iason/Coding/Projects/Approximating shapes with flat "
|
||||
// "patterns/ReducedModelOptimization/TestSet/TileIntoSurface/plane_34Polygons.ply"};
|
||||
// assert(std::filesystem::exists(tileIntoSurfaceFilePath));
|
||||
// pTileIntoSurface->load(tileIntoSurfaceFilePath);
|
||||
|
||||
//Set required file paths
|
||||
const std::filesystem::path tileInto_triMesh_filename
|
||||
= "/home/iason/Coding/build/PatternTillingReducedModel/Meshes/"
|
||||
"instantMeshes_plane_34.ply";
|
||||
const std::filesystem::path reducedPatternFilePath
|
||||
= "/home/iason/Coding/Projects/Approximating shapes with flat "
|
||||
"patterns/ReducedModelOptimization/TestSet/ReducedPatterns/single_reduced.ply";
|
||||
const std::filesystem::path intermediateResultsDirectoryPath
|
||||
= "/home/iason/Coding/build/ReducedModelOptimization/IntermediateResults";
|
||||
// const std::filesystem::path drmSettingsFilePath
|
||||
// = "/home/iason/Coding/Projects/Approximating shapes with flat "
|
||||
// "patterns/ReducedModelOptimization/DefaultSettings/DRMSettings/"
|
||||
// "defaultDRMSimulationSettings.json";
|
||||
DRMSimulationModel::Settings drmSimulationSettings;
|
||||
// drmSimulationSettings.load(drmSettingsFilePath);
|
||||
drmSimulationSettings.linearGuessForceScaleFactor = 1;
|
||||
drmSimulationSettings.debugModeStep = 1000;
|
||||
drmSimulationSettings.beVerbose = true;
|
||||
constexpr bool shouldRerunFullPatternSimulation = false;
|
||||
const std::vector<std::string> scenariosTestSetLabels{"22Hex_randomBending0",
|
||||
"22Hex_randomBending1",
|
||||
"22Hex_randomBending2",
|
||||
"22Hex_randomBending3",
|
||||
"22Hex_randomBending4",
|
||||
"22Hex_randomBending5",
|
||||
"22Hex_randomBending6",
|
||||
"22Hex_randomBending7",
|
||||
"22Hex_randomBending8",
|
||||
"22Hex_randomBending9",
|
||||
"22Hex_randomBending10",
|
||||
"22Hex_randomBending11",
|
||||
"22Hex_randomBending12",
|
||||
"22Hex_randomBending13",
|
||||
"22Hex_randomBending14",
|
||||
"22Hex_randomBending15",
|
||||
"22Hex_randomBending16",
|
||||
"22Hex_randomBending17",
|
||||
"22Hex_randomBending18",
|
||||
"22Hex_randomBending19",
|
||||
"22Hex_randomBending20",
|
||||
"22Hex_bending_0.005N",
|
||||
"22Hex_bending_0.01N",
|
||||
"22Hex_bending_0.03N",
|
||||
"22Hex_bending_0.05N",
|
||||
"22Hex_pullOppositeVerts_0.05N",
|
||||
"22Hex_pullOppositeVerts_0.1N",
|
||||
"22Hex_pullOppositeVerts_0.3N",
|
||||
"22Hex_shear_2N",
|
||||
"22Hex_shear_5N",
|
||||
"22Hex_axial_10N",
|
||||
"22Hex_axial_20N",
|
||||
"22Hex_cylinder_0.05N",
|
||||
"22Hex_cylinder_0.1N",
|
||||
"22Hex_s_0.05N",
|
||||
"22Hex_s_0.1N"};
|
||||
|
||||
//Load surface
|
||||
std::shared_ptr<VCGPolyMesh> pTileIntoSurface = [&]() {
|
||||
ReducedModelEvaluator::ReducedModelEvaluator() {
|
||||
pTileIntoSurface = [&]() {
|
||||
std::istringstream inputStream_tileIntoTriSurface(
|
||||
tileIntoSurfaceFileContent);
|
||||
VCGTriMesh tileInto_triMesh;
|
||||
const bool surfaceLoadSuccessfull = tileInto_triMesh.load(tileInto_triMesh_filename);
|
||||
const bool surfaceLoadSuccessfull =
|
||||
tileInto_triMesh.load(inputStream_tileIntoTriSurface);
|
||||
tileInto_triMesh.setLabel("instantMeshes_plane_34");
|
||||
assert(surfaceLoadSuccessfull);
|
||||
return PolygonalRemeshing::remeshWithPolygons(tileInto_triMesh);
|
||||
}();
|
||||
const double optimizedBaseTriangleHeight = vcg::Distance(optimizationResults.baseTriangle.cP(0),
|
||||
(optimizationResults.baseTriangle.cP(1)
|
||||
+ optimizationResults.baseTriangle.cP(
|
||||
2))
|
||||
/ 2);
|
||||
}
|
||||
|
||||
ReducedModelEvaluator::Results ReducedModelEvaluator::evaluateReducedModel(
|
||||
ReducedModelOptimization::Results& optimizationResult,
|
||||
const Settings& settings) {
|
||||
const std::filesystem::path scenariosDirectoryPath =
|
||||
"/home/iason/Coding/Projects/Approximating shapes with flat "
|
||||
"patterns/ReducedModelEvaluator/Scenarios";
|
||||
const std::filesystem::path fullPatternTessellatedResultsDirectoryPath =
|
||||
"/home/iason/Coding/Projects/Approximating shapes with flat "
|
||||
"patterns/ReducedModelEvaluator/TessellatedResults";
|
||||
|
||||
return evaluateReducedModel(optimizationResult, scenariosDirectoryPath,
|
||||
fullPatternTessellatedResultsDirectoryPath,
|
||||
settings);
|
||||
}
|
||||
|
||||
void ReducedModelEvaluator::printResults(const Results& evaluationResults,
|
||||
const std::string& resultsLabel) {
|
||||
CSVFile csvOutputToCout({}, true);
|
||||
ExportingSettings exportSettings;
|
||||
exportSettings.direction = Vertical;
|
||||
exportSettings.shouldWriteHeader = false;
|
||||
exportSettings.resultsLabel = resultsLabel;
|
||||
printResults(evaluationResults, exportSettings, csvOutputToCout);
|
||||
}
|
||||
|
||||
void ReducedModelEvaluator::printResults(
|
||||
const Results& evaluationResults,
|
||||
const ExportingSettings& exportingSettings,
|
||||
CSVFile& csvOutput) {
|
||||
if (exportingSettings.shouldWriteHeader) {
|
||||
csvOutput << csvExportingDataStrings[exportingSettings.data];
|
||||
printHeader(exportingSettings, csvOutput);
|
||||
csvOutput << endrow;
|
||||
}
|
||||
if (!exportingSettings.resultsLabel.empty()) {
|
||||
csvOutput << exportingSettings.resultsLabel;
|
||||
}
|
||||
if (exportingSettings.direction == Vertical) {
|
||||
printResultsVertically(evaluationResults, csvOutput);
|
||||
} else {
|
||||
printResultsHorizontally(evaluationResults, csvOutput);
|
||||
}
|
||||
}
|
||||
|
||||
void ReducedModelEvaluator::printHeader(
|
||||
const ExportingSettings& exportingSettings,
|
||||
CSVFile& csvOutput) {
|
||||
if (exportingSettings.direction == Horizontal) {
|
||||
// csvOutput << "Job label";
|
||||
for (int jobIndex = 0;
|
||||
jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size();
|
||||
jobIndex++) {
|
||||
const std::string& jobLabel =
|
||||
ReducedModelEvaluator::scenariosTestSetLabels[jobIndex];
|
||||
csvOutput << jobLabel;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Vertical header not defined" << std::endl;
|
||||
assert(false);
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void ReducedModelEvaluator::printResultsHorizontally(
|
||||
const Results& evaluationResults,
|
||||
CSVFile& csvOutput) {
|
||||
// print header
|
||||
// print raw error
|
||||
constexpr bool shouldPrintRawError = false;
|
||||
if (shouldPrintRawError) {
|
||||
double sumOfFull2Reduced = 0;
|
||||
int numOfNonEvaluatedScenarios = 0;
|
||||
for (int jobIndex = 0;
|
||||
jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size();
|
||||
jobIndex++) {
|
||||
const double& distance_fullDrmToReduced =
|
||||
evaluationResults.distances_drm2reduced[jobIndex];
|
||||
if (distance_fullDrmToReduced == -1) {
|
||||
csvOutput << "notEvaluated";
|
||||
numOfNonEvaluatedScenarios++;
|
||||
} else {
|
||||
csvOutput << distance_fullDrmToReduced;
|
||||
sumOfFull2Reduced += distance_fullDrmToReduced;
|
||||
}
|
||||
}
|
||||
}
|
||||
// print normalized error
|
||||
double sumOfNormalizedFull2Reduced = 0;
|
||||
for (int jobIndex = 0;
|
||||
jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size();
|
||||
jobIndex++) {
|
||||
const double& distance_normalizedFullDrmToReduced =
|
||||
evaluationResults.distances_normalizedGroundTruth2reduced[jobIndex];
|
||||
if (distance_normalizedFullDrmToReduced == -1) {
|
||||
csvOutput << "notEvaluated";
|
||||
} else {
|
||||
csvOutput << distance_normalizedFullDrmToReduced;
|
||||
sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReducedModelEvaluator::printResultsVertically(
|
||||
const Results& evaluationResults,
|
||||
CSVFile& csvOutput) {
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
csvOutput << "pattern2Reduced"
|
||||
<< "norm_pattern2Reduced";
|
||||
#else
|
||||
csvOutput << "Job Label"
|
||||
<< "drm2Reduced"
|
||||
<< "norm_drm2Reduced";
|
||||
|
||||
#endif
|
||||
csvOutput << endrow;
|
||||
double sumOfFull2Reduced = 0;
|
||||
double sumOfNormalizedFull2Reduced = 0;
|
||||
int numOfNonEvaluatedScenarios = 0;
|
||||
for (int jobIndex = 0;
|
||||
jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size();
|
||||
jobIndex++) {
|
||||
const double& distance_fullDrmToReduced =
|
||||
evaluationResults.distances_drm2reduced[jobIndex];
|
||||
const double& distance_normalizedFullDrmToReduced =
|
||||
evaluationResults.distances_normalizedGroundTruth2reduced[jobIndex];
|
||||
#ifndef POLYSCOPE_DEFINED
|
||||
const std::string& jobLabel =
|
||||
ReducedModelEvaluator::scenariosTestSetLabels[jobIndex];
|
||||
csvOutput << jobLabel;
|
||||
#endif
|
||||
if (distance_fullDrmToReduced == -1) {
|
||||
csvOutput << "notEvaluated"
|
||||
<< "notEvaluated";
|
||||
numOfNonEvaluatedScenarios++;
|
||||
} else {
|
||||
csvOutput << distance_fullDrmToReduced
|
||||
<< distance_normalizedFullDrmToReduced;
|
||||
sumOfFull2Reduced += distance_fullDrmToReduced;
|
||||
sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced;
|
||||
}
|
||||
csvOutput << endrow;
|
||||
}
|
||||
const int numOfEvaluatedScenarios =
|
||||
ReducedModelEvaluator::scenariosTestSetLabels.size() -
|
||||
numOfNonEvaluatedScenarios;
|
||||
const double averageDistance_full2Reduced =
|
||||
sumOfFull2Reduced / numOfEvaluatedScenarios;
|
||||
const double averageDistance_normalizedFull2Reduced =
|
||||
sumOfNormalizedFull2Reduced / numOfEvaluatedScenarios;
|
||||
#ifndef POLYSCOPE_DEFINED
|
||||
csvOutput << "Average error";
|
||||
#endif
|
||||
csvOutput << averageDistance_full2Reduced
|
||||
<< averageDistance_normalizedFull2Reduced;
|
||||
csvOutput << endrow;
|
||||
#ifndef POLYSCOPE_DEFINED
|
||||
csvOutput << "Cumulative error";
|
||||
#endif
|
||||
csvOutput << sumOfFull2Reduced << sumOfNormalizedFull2Reduced;
|
||||
csvOutput << endrow;
|
||||
csvOutput << endrow;
|
||||
}
|
||||
|
||||
ReducedModelEvaluator::Results ReducedModelEvaluator::evaluateReducedModel(
|
||||
ReducedModelOptimization::Results& optimizationResult,
|
||||
const std::filesystem::path& scenariosDirectoryPath,
|
||||
const std::filesystem::path& patternTessellatedResultsDirectoryPath,
|
||||
const ReducedModelEvaluator::Settings& evaluationSettings) {
|
||||
std::cout << evaluationSettings.toString() << std::endl;
|
||||
// Apply optimization results to the reduced model
|
||||
ReducedModel reducedModel;
|
||||
reducedModel.deleteDanglingVertices();
|
||||
std::unordered_map<std::string, double> optimalXVariables_set(
|
||||
optimizationResult.optimalXNameValuePairs.begin(),
|
||||
optimizationResult.optimalXNameValuePairs.end());
|
||||
reducedModel.updateBaseTriangleGeometry_R(optimalXVariables_set.at("R"));
|
||||
reducedModel.updateBaseTriangleGeometry_theta(
|
||||
optimalXVariables_set.at("Theta"));
|
||||
|
||||
// reducedModel.registerForDrawing();
|
||||
|
||||
// Scale tile-into surface
|
||||
pTileIntoSurface->moveToCenter();
|
||||
const double scaleFactor = optimizedBaseTriangleHeight
|
||||
/ pTileIntoSurface->getAverageFaceRadius();
|
||||
const double scaleFactor =
|
||||
optimizationResult.settings.targetBaseTriangleSize /
|
||||
pTileIntoSurface->getAverageFaceRadius();
|
||||
vcg::tri::UpdatePosition<VCGPolyMesh>::Scale(*pTileIntoSurface, scaleFactor);
|
||||
// tileIntoSurface.registerForDrawing();
|
||||
// polyscope::show();
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
pTileIntoSurface->registerForDrawing(color_tileIntoSurface, false);
|
||||
#endif
|
||||
|
||||
// Tile full pattern into surface
|
||||
std::vector<PatternGeometry> fullPatterns(1);
|
||||
fullPatterns[0].copy(optimizationResults.baseTriangleFullPattern);
|
||||
//// Base triangle pattern might contain dangling vertices.Remove those
|
||||
fullPatterns[0].interfaceNodeIndex = 3;
|
||||
fullPatterns[0].deleteDanglingVertices();
|
||||
std::vector<PatternGeometry> patterns(1);
|
||||
patterns[0].copy(optimizationResult.baseTrianglePattern);
|
||||
patterns[0].interfaceNodeIndex = 3;
|
||||
patterns[0].deleteDanglingVertices();
|
||||
std::vector<int> perSurfaceFacePatternIndices(pTileIntoSurface->FN(), 0);
|
||||
std::vector<std::vector<size_t>> perPatternIndexTiledFullPatternEdgeIndices;
|
||||
std::vector<size_t> tileIntoEdgeToTiledFullVi;
|
||||
std::shared_ptr<PatternGeometry> pTiledFullPattern
|
||||
= PatternGeometry::tilePattern(fullPatterns,
|
||||
{},
|
||||
*pTileIntoSurface,
|
||||
std::shared_ptr<PatternGeometry> pTilled_pattern =
|
||||
PatternGeometry::tilePattern(patterns, {}, *pTileIntoSurface,
|
||||
perSurfaceFacePatternIndices,
|
||||
tileIntoEdgeToTiledFullVi,
|
||||
perPatternIndexTiledFullPatternEdgeIndices);
|
||||
pTiledFullPattern->setLabel("Tiled_full_patterns");
|
||||
// pTiledFullPattern->registerForDrawing();
|
||||
//Tile reduced pattern into surface
|
||||
PatternGeometry reducedPattern;
|
||||
reducedPattern.load(reducedPatternFilePath);
|
||||
reducedPattern.deleteDanglingVertices();
|
||||
assert(reducedPattern.interfaceNodeIndex == 1);
|
||||
std::vector<PatternGeometry> reducedPatterns(1);
|
||||
reducedPatterns[0].copy(reducedPattern);
|
||||
const auto reducedPatternBaseTriangle = reducedPattern.computeBaseTriangle();
|
||||
ReducedModelOptimization::Results::applyOptimizationResults_innerHexagon(
|
||||
optimizationResults, reducedPatternBaseTriangle, reducedPatterns[0]);
|
||||
pTilled_pattern->setLabel("Tilled_pattern");
|
||||
|
||||
std::vector<std::vector<size_t>> perPatternIndexTiledReducedPatternEdgeIndices;
|
||||
// Tile reduced pattern into surface
|
||||
std::vector<PatternGeometry> reducedModels(1);
|
||||
reducedModels[0].copy(reducedModel);
|
||||
std::vector<std::vector<size_t>>
|
||||
perPatternIndexTiledReducedPatternEdgeIndices;
|
||||
std::vector<size_t> tileIntoEdgeToTiledReducedVi;
|
||||
std::shared_ptr<PatternGeometry> pTiledReducedPattern
|
||||
= PatternGeometry::tilePattern(reducedPatterns,
|
||||
{0},
|
||||
*pTileIntoSurface,
|
||||
perSurfaceFacePatternIndices,
|
||||
std::shared_ptr<PatternGeometry> pTilled_reducedModel =
|
||||
PatternGeometry::tilePattern(
|
||||
reducedModels, {0}, *pTileIntoSurface, perSurfaceFacePatternIndices,
|
||||
tileIntoEdgeToTiledReducedVi,
|
||||
perPatternIndexTiledReducedPatternEdgeIndices);
|
||||
pTiledReducedPattern->setLabel("Tiled_reduced_patterns");
|
||||
// pTiledReducedPattern->registerForDrawing();
|
||||
pTilled_reducedModel->setLabel("Tilled_reduced_model");
|
||||
|
||||
std::unordered_map<FullPatternVertexIndex, ReducedPatternVertexIndex>
|
||||
fullToReducedViMap; //of only the common vertices
|
||||
std::unordered_map<ReducedPatternVertexIndex, FullPatternVertexIndex>
|
||||
std::unordered_map<PatternVertexIndex, ReducedModelVertexIndex>
|
||||
patternToReducedViMap; // of only the common vertices
|
||||
std::unordered_map<ReducedModelVertexIndex, PatternVertexIndex>
|
||||
reducedToFullViMap; // of only the common vertices
|
||||
for (int ei = 0; ei < pTileIntoSurface->EN(); ei++) {
|
||||
fullToReducedViMap[tileIntoEdgeToTiledFullVi[ei]] = tileIntoEdgeToTiledReducedVi[ei];
|
||||
patternToReducedViMap[tileIntoEdgeToTiledFullVi[ei]] =
|
||||
tileIntoEdgeToTiledReducedVi[ei];
|
||||
}
|
||||
constructInverseMap(fullToReducedViMap, reducedToFullViMap);
|
||||
constructInverseMap(patternToReducedViMap, reducedToFullViMap);
|
||||
|
||||
std::vector<size_t> tilledFullPatternInterfaceVi;
|
||||
tilledFullPatternInterfaceVi.clear();
|
||||
tilledFullPatternInterfaceVi.resize(fullToReducedViMap.size());
|
||||
tilledFullPatternInterfaceVi.resize(patternToReducedViMap.size());
|
||||
size_t viIndex = 0;
|
||||
for (std::pair<size_t, size_t> fullToReducedPair : fullToReducedViMap) {
|
||||
for (std::pair<size_t, size_t> fullToReducedPair : patternToReducedViMap) {
|
||||
tilledFullPatternInterfaceVi[viIndex++] = fullToReducedPair.first;
|
||||
}
|
||||
|
||||
// Create simulation meshes
|
||||
////Tessellated full pattern simulation mesh
|
||||
std::shared_ptr<SimulationMesh> pTiledFullPattern_simulationMesh;
|
||||
pTiledFullPattern_simulationMesh = std::make_shared<SimulationMesh>(*pTiledFullPattern);
|
||||
//NOTE: Those should be derived from the optimization results instead of hardcoding them
|
||||
pTiledFullPattern_simulationMesh->setBeamCrossSection(CrossSectionType{0.002, 0.002});
|
||||
if (optimizationResults.fullPatternYoungsModulus == 0) {
|
||||
std::shared_ptr<SimulationEdgeMesh> pSimulationEdgeMesh_tilledPattern =
|
||||
std::make_shared<SimulationEdgeMesh>(*pTilled_pattern);
|
||||
pSimulationEdgeMesh_tilledPattern->setBeamCrossSection(
|
||||
optimizationResult.settings.beamDimensions_pattern);
|
||||
if (optimizationResult.settings.youngsModulus_pattern == 0) {
|
||||
std::cerr << "Full pattern's young modulus not found." << std::endl;
|
||||
std::terminate();
|
||||
}
|
||||
pTiledFullPattern_simulationMesh->setBeamMaterial(0.3,
|
||||
optimizationResults.fullPatternYoungsModulus);
|
||||
pTiledFullPattern_simulationMesh->reset();
|
||||
pSimulationEdgeMesh_tilledPattern->setBeamMaterial(
|
||||
0.3, optimizationResult.settings.youngsModulus_pattern);
|
||||
pSimulationEdgeMesh_tilledPattern->reset();
|
||||
// optimizationResult.draw();
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
pSimulationEdgeMesh_tilledPattern->registerForDrawing(
|
||||
color_tesselatedPatterns);
|
||||
#endif
|
||||
|
||||
////Tessellated reduced pattern simulation mesh
|
||||
std::shared_ptr<SimulationMesh> pTiledReducedPattern_simulationMesh;
|
||||
pTiledReducedPattern_simulationMesh = std::make_shared<SimulationMesh>(*pTiledReducedPattern);
|
||||
const std::vector<size_t> &tiledPatternElementIndicesForReducedPattern
|
||||
= perPatternIndexTiledReducedPatternEdgeIndices[0];
|
||||
std::shared_ptr<SimulationEdgeMesh> pSimulationEdgeMesh_tilledReducedModel;
|
||||
pSimulationEdgeMesh_tilledReducedModel =
|
||||
std::make_shared<SimulationEdgeMesh>(*pTilled_reducedModel);
|
||||
ReducedModelOptimization::Results::applyOptimizationResults_elements(
|
||||
optimizationResults, pTiledReducedPattern_simulationMesh);
|
||||
pTiledReducedPattern_simulationMesh->reset();
|
||||
std::vector<double> distances_drm2reduced(scenariosTestSetLabels.size(), 0);
|
||||
std::vector<double> distances_normalizedDrm2reduced(scenariosTestSetLabels.size(), 0);
|
||||
for (int jobIndex = 0; jobIndex < scenariosTestSetLabels.size(); jobIndex++) {
|
||||
const std::string &jobLabel = scenariosTestSetLabels[jobIndex];
|
||||
const std::filesystem::path scenariosDirectoryPath
|
||||
= "/home/iason/Coding/build/PatternTillingReducedModel/Scenarios/";
|
||||
const std::filesystem::path tiledReducedPatternJobFilePath
|
||||
= std::filesystem::path(scenariosDirectoryPath)
|
||||
optimizationResult, pSimulationEdgeMesh_tilledReducedModel);
|
||||
pSimulationEdgeMesh_tilledReducedModel->reset();
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
pSimulationEdgeMesh_tilledReducedModel->registerForDrawing(
|
||||
color_tesselatedReducedModels, false,
|
||||
pSimulationEdgeMesh_tilledPattern->elements[0]
|
||||
.dimensions.getDrawingRadius());
|
||||
#endif
|
||||
|
||||
Results evaluationResults;
|
||||
evaluationResults.evaluationScenarioLabels = scenariosTestSetLabels;
|
||||
evaluationResults.distances_drm2reduced.fill(-1);
|
||||
evaluationResults.distances_normalizedGroundTruth2reduced.fill(-1);
|
||||
DRMSimulationModel::Settings drmSimulationSettings;
|
||||
// drmSimulationSettings.threshold_residualToExternalForcesNorm = 1e-3;
|
||||
// drmSimulationSettings.load(drmSettingsFilePath);
|
||||
drmSimulationSettings.beVerbose = evaluationSettings.beVerbose;
|
||||
drmSimulationSettings.maxDRMIterations = 5e6;
|
||||
drmSimulationSettings.debugModeStep = 100000;
|
||||
drmSimulationSettings.threshold_totalTranslationalKineticEnergy = 1e-14;
|
||||
// drmSimulationSettings.threshold_currentToFirstPeakTranslationalKineticEnergy
|
||||
// =
|
||||
// 1e-10;
|
||||
drmSimulationSettings.threshold_averageResidualToExternalForcesNorm = 1e-5;
|
||||
// drmSimulationSettings.linearGuessForceScaleFactor = 0.8;
|
||||
// drmSimulationSettings.viscousDampingFactor = 7e-3;
|
||||
// drmSimulationSettings.xi = 0.9999;
|
||||
// drmSimulationSettings.gamma = 0.25;
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
// drmSimulationSettings.shouldDraw = true;
|
||||
drmSimulationSettings.shouldCreatePlots = false;
|
||||
if (evaluationSettings.shouldDraw) {
|
||||
pSimulationEdgeMesh_tilledPattern->registerForDrawing(
|
||||
ReducedModelOptimization::Colors::patternInitial, true);
|
||||
}
|
||||
#endif
|
||||
const std::string& simulationModelLabel_pattern =
|
||||
optimizationResult.settings.simulationModelLabel_groundTruth;
|
||||
const std::string& simulationModelLabel_reducedModel =
|
||||
optimizationResult.settings.simulationModelLabel_reducedModel;
|
||||
// ChronosEulerLinearSimulationModel::label;
|
||||
|
||||
std::for_each(
|
||||
#ifndef POLYSCOPE_DEFINED
|
||||
std::execution::par_unseq,
|
||||
#endif
|
||||
scenariosTestSetLabels.begin(), scenariosTestSetLabels.end(),
|
||||
[&](const std::string& jobLabel) {
|
||||
// check if reduced model scenario exists
|
||||
// const std::string &jobLabel =
|
||||
// scenariosTestSetLabels[jobIndex];
|
||||
const std::filesystem::path tiledReducedPatternJobFilePath =
|
||||
std::filesystem::path(scenariosDirectoryPath)
|
||||
.append(pTileIntoSurface->getLabel())
|
||||
.append(jobLabel)
|
||||
.append("SimulationJobs")
|
||||
.append("Reduced")
|
||||
.append("ReducedJob")
|
||||
.append(SimulationJob::jsonDefaultFileName);
|
||||
if (!std::filesystem::exists(tiledReducedPatternJobFilePath)) {
|
||||
if (evaluationSettings.beVerbose) {
|
||||
std::cerr << "Scenario " << jobLabel
|
||||
<< " not found in:" << tiledReducedPatternJobFilePath
|
||||
<< std::endl;
|
||||
}
|
||||
// continue; //if not move on to the next scenario
|
||||
return;
|
||||
}
|
||||
// Map the reduced job to the job on the pattern tessellation
|
||||
// set jobs
|
||||
std::shared_ptr<SimulationJob> pJob_tiledReducedPattern;
|
||||
pJob_tiledReducedPattern = std::make_shared<SimulationJob>(SimulationJob());
|
||||
pJob_tiledReducedPattern->load(tiledReducedPatternJobFilePath, false);
|
||||
pJob_tiledReducedPattern->pMesh = pTiledReducedPattern_simulationMesh;
|
||||
std::shared_ptr<SimulationJob> pJob_tiledFullPattern;
|
||||
pJob_tiledFullPattern = std::make_shared<SimulationJob>(SimulationJob());
|
||||
pJob_tiledFullPattern->pMesh = pTiledFullPattern_simulationMesh;
|
||||
pJob_tiledReducedPattern->remap(reducedToFullViMap, *pJob_tiledFullPattern);
|
||||
std::shared_ptr<SimulationJob> pJob_tiledReducedModel;
|
||||
pJob_tiledReducedModel =
|
||||
std::make_shared<SimulationJob>(SimulationJob());
|
||||
pJob_tiledReducedModel->load(tiledReducedPatternJobFilePath, false);
|
||||
std::for_each(pJob_tiledReducedModel->nodalExternalForces.begin(),
|
||||
pJob_tiledReducedModel->nodalExternalForces.end(),
|
||||
[&](std::pair<const VertexIndex, Vector6d>& viForcePair) {
|
||||
viForcePair.second =
|
||||
viForcePair.second * forceScalingFactor;
|
||||
});
|
||||
pJob_tiledReducedModel->pMesh = pSimulationEdgeMesh_tilledReducedModel;
|
||||
std::shared_ptr<SimulationJob> pJob_tilledPattern;
|
||||
pJob_tilledPattern = std::make_shared<SimulationJob>(SimulationJob());
|
||||
pJob_tilledPattern->pMesh = pSimulationEdgeMesh_tilledPattern;
|
||||
pJob_tiledReducedModel->remap(reducedToFullViMap, *pJob_tilledPattern);
|
||||
// pJob_tiledReducedPattern->registerForDrawing(pTiledReducedPattern->getLabel());
|
||||
// pJob_tiledFullPattern->registerForDrawing(pTiledFullPattern->getLabel());
|
||||
// polyscope::show();
|
||||
const std::filesystem::path surfaceFolderPath =
|
||||
std::filesystem::path(patternTessellatedResultsDirectoryPath)
|
||||
.append(simulationModelLabel_pattern + "_" +
|
||||
pTileIntoSurface->getLabel());
|
||||
const std::string scenarioLabel = pJob_tilledPattern->getLabel();
|
||||
const std::filesystem::path scenarioDirectoryPath =
|
||||
std::filesystem::path(surfaceFolderPath).append(scenarioLabel);
|
||||
// Save reduced job
|
||||
const std::filesystem::path tesellatedResultsFolderPath
|
||||
= std::filesystem::path(intermediateResultsDirectoryPath).append("TessellatedResults");
|
||||
const std::filesystem::path surfaceFolderPath = std::filesystem::path(
|
||||
tesellatedResultsFolderPath)
|
||||
.append(pTileIntoSurface->getLabel());
|
||||
const std::string scenarioLabel = pJob_tiledFullPattern->getLabel();
|
||||
const std::filesystem::path scenarioDirectoryPath = std::filesystem::path(surfaceFolderPath)
|
||||
.append(scenarioLabel);
|
||||
const std::filesystem::path reducedJobDirectoryPath
|
||||
= std::filesystem::path(scenarioDirectoryPath).append("ReducedJob");
|
||||
constexpr bool exportReducedJob = false;
|
||||
if (exportReducedJob) {
|
||||
const std::filesystem::path reducedJobDirectoryPath =
|
||||
std::filesystem::path(scenarioDirectoryPath).append("ReducedJob");
|
||||
std::filesystem::create_directories(reducedJobDirectoryPath);
|
||||
pJob_tiledReducedPattern->save(reducedJobDirectoryPath);
|
||||
//Run scenario
|
||||
|
||||
pJob_tiledReducedModel->save(reducedJobDirectoryPath);
|
||||
}
|
||||
// Check if the drm simulation of the full pattern has already been
|
||||
// computed
|
||||
////Full
|
||||
|
||||
const std::string patternLabel = [&]() {
|
||||
const std::string patternLabel = optimizationResults.baseTriangleFullPattern.getLabel();
|
||||
const int numberOfOccurences = std::count_if(patternLabel.begin(),
|
||||
patternLabel.end(),
|
||||
[](char c) { return c == '#'; });
|
||||
if (numberOfOccurences == 0) {
|
||||
return std::to_string(optimizationResults.baseTriangleFullPattern.EN()) + "#"
|
||||
+ optimizationResults.baseTriangleFullPattern.getLabel();
|
||||
} else if (numberOfOccurences == 1) {
|
||||
return optimizationResults.baseTriangleFullPattern.getLabel();
|
||||
const std::string& patternLabel = [&]() {
|
||||
const std::string patternLabel =
|
||||
optimizationResult.baseTrianglePattern.getLabel();
|
||||
if (patternLabel.find("_") == std::string::npos) {
|
||||
return std::to_string(optimizationResult.baseTrianglePattern.EN()) +
|
||||
"_" + patternLabel;
|
||||
} else {
|
||||
return patternLabel;
|
||||
}
|
||||
}();
|
||||
const auto fullResultsFolderPath
|
||||
= std::filesystem::path(scenarioDirectoryPath).append(patternLabel).append("Results");
|
||||
if (shouldRerunFullPatternSimulation && std::filesystem::exists(fullResultsFolderPath)) {
|
||||
std::filesystem::remove_all(fullResultsFolderPath);
|
||||
const auto tilledPatternResultsFolderPath =
|
||||
std::filesystem::path(scenarioDirectoryPath)
|
||||
.append(patternLabel)
|
||||
.append("Results");
|
||||
if (evaluationSettings.shouldRecomputeGroundTruthResults &&
|
||||
std::filesystem::exists(tilledPatternResultsFolderPath)) {
|
||||
std::filesystem::remove_all(tilledPatternResultsFolderPath);
|
||||
}
|
||||
|
||||
const std::filesystem::path fullPatternJobFolderPath = std::filesystem::path(
|
||||
scenarioDirectoryPath)
|
||||
const std::filesystem::path fullPatternJobFolderPath =
|
||||
std::filesystem::path(scenarioDirectoryPath)
|
||||
.append(patternLabel)
|
||||
.append("SimulationJob");
|
||||
SimulationResults simulationResults_tiledFullPattern_drm;
|
||||
if (std::filesystem::exists(fullResultsFolderPath)) {
|
||||
SimulationResults simulationResults_tilledPattern;
|
||||
if (std::filesystem::exists(tilledPatternResultsFolderPath)) {
|
||||
// Load full pattern results
|
||||
assert(std::filesystem::exists(fullPatternJobFolderPath));
|
||||
simulationResults_tiledFullPattern_drm.load(fullResultsFolderPath,
|
||||
simulationResults_tilledPattern.load(tilledPatternResultsFolderPath,
|
||||
fullPatternJobFolderPath);
|
||||
simulationResults_tiledFullPattern_drm.converged = true;
|
||||
|
||||
simulationResults_tilledPattern.converged = true;
|
||||
} else {
|
||||
//Full
|
||||
if (evaluationSettings.beVerbose) {
|
||||
std::cout << "Executing:" << jobLabel << std::endl;
|
||||
DRMSimulationModel drmSimulationModel;
|
||||
simulationResults_tiledFullPattern_drm
|
||||
= drmSimulationModel.executeSimulation(pJob_tiledFullPattern, drmSimulationSettings);
|
||||
simulationResults_tiledFullPattern_drm.setLabelPrefix("DRM");
|
||||
}
|
||||
std::filesystem::create_directories(fullResultsFolderPath);
|
||||
simulationResults_tiledFullPattern_drm.save(
|
||||
std::filesystem::path(scenarioDirectoryPath).append(patternLabel));
|
||||
if (!simulationResults_tiledFullPattern_drm.converged) {
|
||||
SimulationModelFactory factory;
|
||||
std::unique_ptr<SimulationModel> pTilledPatternSimulationModel =
|
||||
factory.create(simulationModelLabel_pattern);
|
||||
// TODO: since the drm simulation model does not have a common
|
||||
// interface with the rest of simulation models I need to cast it in
|
||||
// order to pass simulation settings. Fix it by removing the
|
||||
// SimulationSettings argument
|
||||
if (simulationModelLabel_pattern == DRMSimulationModel::label) {
|
||||
simulationResults_tilledPattern =
|
||||
reinterpret_cast<DRMSimulationModel*>(
|
||||
pTilledPatternSimulationModel.get())
|
||||
->executeSimulation(pJob_tilledPattern,
|
||||
drmSimulationSettings);
|
||||
} else {
|
||||
simulationResults_tilledPattern =
|
||||
pTilledPatternSimulationModel->executeSimulation(
|
||||
pJob_tilledPattern);
|
||||
}
|
||||
}
|
||||
if (!simulationResults_tilledPattern.converged) {
|
||||
std::cerr << "Full pattern simulation failed." << std::endl;
|
||||
std::cerr << "Not saving results" << std::endl;
|
||||
// continue;
|
||||
return;
|
||||
}
|
||||
std::filesystem::create_directories(tilledPatternResultsFolderPath);
|
||||
const std::filesystem::path drmResultsOutputPath =
|
||||
std::filesystem::path(scenarioDirectoryPath).append(patternLabel);
|
||||
simulationResults_tilledPattern.save(drmResultsOutputPath);
|
||||
|
||||
LinearSimulationModel linearSimulationModel;
|
||||
SimulationResults simulationResults_tiledReducedPattern
|
||||
= linearSimulationModel.executeSimulation(pJob_tiledReducedPattern);
|
||||
// LinearSimulationModel linearSimulationModel;
|
||||
SimulationModelFactory factory;
|
||||
std::unique_ptr<SimulationModel> pSimulationModel_tilledReducedModel =
|
||||
factory.create(simulationModelLabel_reducedModel);
|
||||
SimulationResults simulationResults_tiledReducedModel =
|
||||
pSimulationModel_tilledReducedModel->executeSimulation(
|
||||
pJob_tiledReducedModel);
|
||||
|
||||
// simulationResults_tiledReducedPattern.registerForDrawing();
|
||||
// simulationResults_tiledFullPattern_drm.registerForDrawing();
|
||||
// polyscope::show();
|
||||
//measure distance
|
||||
const double distance_fullDrmToReduced
|
||||
= simulationResults_tiledFullPattern_drm
|
||||
.computeDistance(simulationResults_tiledReducedPattern, fullToReducedViMap);
|
||||
double distance_fullSumOfAllVerts = 0;
|
||||
for (std::pair<size_t, size_t> fullToReducedPair : fullToReducedViMap) {
|
||||
distance_fullSumOfAllVerts += simulationResults_tiledFullPattern_drm
|
||||
.displacements[fullToReducedPair.first]
|
||||
// ChronosEulerNonLinearSimulationModel
|
||||
// debug_chronosNonLinearSimulationModel;
|
||||
// const auto debug_chronosResults =
|
||||
// debug_chronosNonLinearSimulationModel.executeSimulation(
|
||||
// pJob_tilledPattern);
|
||||
// LinearSimulationModel debug_linearSimulationModel;
|
||||
// const auto debug_linearSimResults =
|
||||
// debug_linearSimulationModel.executeSimulation(pJob_tilledPattern);
|
||||
|
||||
const int jobIndex = &jobLabel - &scenariosTestSetLabels[0];
|
||||
evaluationResults.maxDisplacements[jobIndex] =
|
||||
std::max_element(
|
||||
simulationResults_tilledPattern.displacements.begin(),
|
||||
simulationResults_tilledPattern.displacements.end(),
|
||||
[](const Vector6d& d1, const Vector6d& d2) {
|
||||
return d1.getTranslation().norm() <
|
||||
d2.getTranslation().norm();
|
||||
})
|
||||
->getTranslation()
|
||||
.norm();
|
||||
const std::vector<double> distance_perVertexPatternToReduced =
|
||||
SimulationResults::computeDistance_PerVertex(
|
||||
simulationResults_tilledPattern,
|
||||
simulationResults_tiledReducedModel, patternToReducedViMap);
|
||||
std::vector<double> distance_normalizedPerVertexPatternToReduced =
|
||||
distance_perVertexPatternToReduced;
|
||||
// compute the full2reduced distance
|
||||
double distance_patternSumOfAllVerts = 0;
|
||||
for (const std::pair<size_t, size_t>& fullToReducedPair :
|
||||
patternToReducedViMap) {
|
||||
VertexIndex patternVi = fullToReducedPair.first;
|
||||
const double patternVertexDisplacement =
|
||||
simulationResults_tilledPattern.displacements[patternVi]
|
||||
.getTranslation()
|
||||
.norm();
|
||||
distance_patternSumOfAllVerts += patternVertexDisplacement;
|
||||
}
|
||||
const double distance_normalizedFullDrmToReduced = distance_fullDrmToReduced
|
||||
/ distance_fullSumOfAllVerts;
|
||||
distances_drm2reduced[jobIndex] = distance_fullDrmToReduced;
|
||||
distances_normalizedDrm2reduced[jobIndex] = distance_normalizedFullDrmToReduced;
|
||||
int pairIndex = 0;
|
||||
for (const std::pair<size_t, size_t>& fullToReducedPair :
|
||||
patternToReducedViMap) {
|
||||
VertexIndex patternVi = fullToReducedPair.first;
|
||||
const double patternVertexDisplacement =
|
||||
simulationResults_tilledPattern.displacements[patternVi]
|
||||
.getTranslation()
|
||||
.norm();
|
||||
distance_normalizedPerVertexPatternToReduced[pairIndex] =
|
||||
distance_perVertexPatternToReduced[pairIndex] /
|
||||
evaluationResults.maxDisplacements[jobIndex];
|
||||
assert(!std::isnan(
|
||||
distance_normalizedPerVertexPatternToReduced[pairIndex]));
|
||||
pairIndex++;
|
||||
}
|
||||
//#ifndef POLYSCOPE_DEFINED
|
||||
// return distances_drm2reduced;
|
||||
//#else
|
||||
|
||||
//report distance
|
||||
// csvFile csv_results("", flse);
|
||||
csvFile csv_results({}, false);
|
||||
// csvFile csv_results(std::filesystem::path(dirPath_thisOptimization)
|
||||
// .append("results.csv")
|
||||
// .string(),
|
||||
double distance_averageNormalizedPerVertexPatternToReduced =
|
||||
std::accumulate(
|
||||
distance_normalizedPerVertexPatternToReduced.begin(),
|
||||
distance_normalizedPerVertexPatternToReduced.end(), 0.0) /
|
||||
patternToReducedViMap.size();
|
||||
const double distance_patternToReduced =
|
||||
simulationResults_tilledPattern.computeDistance_comulative(
|
||||
simulationResults_tiledReducedModel, patternToReducedViMap);
|
||||
const double distance_normalizedPatternToReduced =
|
||||
distance_patternToReduced / distance_patternSumOfAllVerts;
|
||||
evaluationResults.distances_drm2reduced[jobIndex] =
|
||||
distance_patternToReduced;
|
||||
// evaluationResults.distances_normalizedGroundTruth2reduced[jobIndex]
|
||||
// =
|
||||
// distance_normalizedPatternToReduced;
|
||||
evaluationResults.distances_normalizedGroundTruth2reduced[jobIndex] =
|
||||
distance_averageNormalizedPerVertexPatternToReduced;
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
if (evaluationSettings.shouldDraw) {
|
||||
std::cout << "maxError/maxDisp="
|
||||
<< *std::max_element(
|
||||
distance_perVertexPatternToReduced.begin(),
|
||||
distance_perVertexPatternToReduced.end()) /
|
||||
evaluationResults.maxDisplacements[jobIndex]
|
||||
<< std::endl;
|
||||
std::cout << "max displacement:"
|
||||
<< evaluationResults.maxDisplacements[jobIndex]
|
||||
<< std::endl;
|
||||
std::cout << "average normalized per vertex:"
|
||||
<< distance_averageNormalizedPerVertexPatternToReduced
|
||||
<< std::endl;
|
||||
simulationResults_tiledReducedModel.registerForDrawing(
|
||||
ReducedModelOptimization::Colors::reducedDeformed, false,
|
||||
simulationResults_tilledPattern.pJob->pMesh
|
||||
->getBeamDimensions()[0]
|
||||
.getDrawingRadius());
|
||||
polyscope::CurveNetwork* patternHandle =
|
||||
simulationResults_tilledPattern.registerForDrawing(
|
||||
ReducedModelOptimization::Colors::patternDeformed);
|
||||
pJob_tilledPattern->registerForDrawing(patternHandle->name, true);
|
||||
pJob_tilledPattern->registerForDrawing(
|
||||
pSimulationEdgeMesh_tilledPattern->getLabel(), false);
|
||||
std::vector<double> distances_perVertexAverage(
|
||||
pSimulationEdgeMesh_tilledPattern->VN(), 0.0);
|
||||
int interfaceVi = 0;
|
||||
for (const std::pair<size_t, size_t>& fullToReducedPair :
|
||||
patternToReducedViMap) {
|
||||
VertexIndex patternVi = fullToReducedPair.first;
|
||||
distances_perVertexAverage[patternVi] =
|
||||
distance_normalizedPerVertexPatternToReduced[interfaceVi++];
|
||||
}
|
||||
|
||||
// patternHandle
|
||||
// ->addNodeScalarQuantity(
|
||||
// "average normalized distance "
|
||||
// "per vertex ",
|
||||
// distances_perVertexAverage)
|
||||
// ->setEnabled(true);
|
||||
|
||||
// pJob_tiledReducedModel->registerForDrawing(
|
||||
// pSimulationEdgeMesh_tilledReducedModel->getLabel());
|
||||
// debug_chronosResults.registerForDrawing();
|
||||
// debug_linearSimResults.registerForDrawing();
|
||||
std::cout << "normalized distance pattern2reduced:"
|
||||
<< distance_normalizedPatternToReduced << std::endl;
|
||||
// std::filesystem::path outputFolderPath(
|
||||
// "/home/iason/Documents/PhD/Thesis/images/RME/scenarios/"
|
||||
// "screenshots/");
|
||||
polyscope::show();
|
||||
// const std::string screenshotOutputFilePath_custom =
|
||||
// (std::filesystem::path(outputFolderPath)
|
||||
// .append(optimizationResult.label + "_" +
|
||||
// pJob_tilledPattern->getLabel()))
|
||||
// .string() +
|
||||
// "_custom"
|
||||
// ".png";
|
||||
// polyscope::screenshot(screenshotOutputFilePath_custom,
|
||||
// false);
|
||||
csv_results /*<< "Job Label"*/
|
||||
<< "drm2Reduced"
|
||||
<< "norm_drm2Reduced";
|
||||
csv_results << endrow;
|
||||
double sumOfNormalizedFull2Reduced = 0;
|
||||
for (int jobIndex = 0; jobIndex < scenariosTestSetLabels.size(); jobIndex++) {
|
||||
const std::string &jobLabel = scenariosTestSetLabels[jobIndex];
|
||||
const double &distance_fullDrmToReduced = distances_drm2reduced[jobIndex];
|
||||
const double &distance_normalizedFullDrmToReduced = distances_normalizedDrm2reduced[jobIndex];
|
||||
csv_results /*<< jobLabel*/ << distance_fullDrmToReduced
|
||||
<< distance_normalizedFullDrmToReduced;
|
||||
csv_results << endrow;
|
||||
sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced;
|
||||
// top
|
||||
// const std::filesystem::path jsonFilePath_topView(
|
||||
// "/home/iason/Documents/PhD/Thesis/images/RME/scenarios/"
|
||||
// "cammeraSettings_.json");
|
||||
// std::ifstream f_top(jsonFilePath_topView);
|
||||
// polyscope::view::setCameraFromJson(
|
||||
// nlohmann::json::parse(f_top).dump(), false);
|
||||
// // polyscope::show();
|
||||
// const std::string screenshotOutputFilePath_top =
|
||||
// (std::filesystem::path(outputFolderPath)
|
||||
// .append(optimizationResult.label + "_" +
|
||||
// pJob_tilledPattern->getLabel()))
|
||||
// .string() +
|
||||
// "_top"
|
||||
// ".png";
|
||||
// std::cout << "Saving image to:" <<
|
||||
// screenshotOutputFilePath_top
|
||||
// << std::endl;
|
||||
// polyscope::screenshot(screenshotOutputFilePath_top,
|
||||
// false);
|
||||
// side
|
||||
// const std::filesystem::path jsonFilePath_sideView(
|
||||
// "/home/iason/Documents/PhD/Thesis/images/RME/scenarios/"
|
||||
// "cammeraSettings_sideView.json");
|
||||
// std::ifstream f_side(jsonFilePath_sideView);
|
||||
// polyscope::view::setCameraFromJson(
|
||||
// nlohmann::json::parse(f_side).dump(), false);
|
||||
// // polyscope::show();
|
||||
// const std::string screenshotOutputFilePath_side =
|
||||
// (std::filesystem::path(outputFolderPath)
|
||||
// .append(optimizationResult.label + "_" +
|
||||
// pJob_tilledPattern->getLabel()))
|
||||
// .string() +
|
||||
// "_side"
|
||||
// ".png";
|
||||
// std::cout << "Saving image to:" <<
|
||||
// screenshotOutputFilePath_side
|
||||
// << std::endl;
|
||||
// polyscope::screenshot(screenshotOutputFilePath_side,
|
||||
// false);
|
||||
pJob_tilledPattern->unregister(
|
||||
pSimulationEdgeMesh_tilledPattern->getLabel());
|
||||
pJob_tiledReducedModel->unregister(
|
||||
pSimulationEdgeMesh_tilledReducedModel->getLabel());
|
||||
// debug_linearSimResults.unregister();
|
||||
simulationResults_tiledReducedModel.unregister();
|
||||
simulationResults_tilledPattern.unregister();
|
||||
// debug_chronosResults.unregister();
|
||||
}
|
||||
#endif
|
||||
});
|
||||
|
||||
return evaluationResults;
|
||||
}
|
||||
|
||||
std::cout << "Average normalized error per scenario:"
|
||||
<< sumOfNormalizedFull2Reduced / scenariosTestSetLabels.size() << std::endl;
|
||||
return distances_normalizedDrm2reduced;
|
||||
//#endif
|
||||
bool ReducedModelEvaluator::Settings::save(
|
||||
const std::filesystem::path& jsonFilePath) const {
|
||||
if (std::filesystem::path(jsonFilePath).extension() != ".json") {
|
||||
std::cerr << "A json file is expected as input. The given file has the "
|
||||
"following extension:"
|
||||
<< std::filesystem::path(jsonFilePath).extension() << std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
nlohmann::json json = *this;
|
||||
std::ofstream jsonFile(jsonFilePath.string());
|
||||
jsonFile << json;
|
||||
jsonFile.close();
|
||||
}
|
||||
|
||||
bool ReducedModelEvaluator::Settings::load(
|
||||
const std::filesystem::path& jsonFilePath) {
|
||||
if (!std::filesystem::exists(jsonFilePath)) {
|
||||
std::cerr << "Evaluation settings could not be loaded because input "
|
||||
"filepath does "
|
||||
"not exist:"
|
||||
<< jsonFilePath << std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::filesystem::path(jsonFilePath).extension() != ".json") {
|
||||
std::cerr << "A json file is expected as input. The given file has the "
|
||||
"following extension:"
|
||||
<< std::filesystem::path(jsonFilePath).extension() << std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream ifs(jsonFilePath);
|
||||
nlohmann::json json;
|
||||
ifs >> json;
|
||||
*this = json;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,13 +2,250 @@
|
|||
#define REDUCEDMODELEVALUATOR_HPP
|
||||
|
||||
#include "reducedmodeloptimizer_structs.hpp"
|
||||
#include "utilities.hpp"
|
||||
|
||||
class ReducedModelEvaluator
|
||||
{
|
||||
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();
|
||||
static std::vector<double> evaluateReducedModel(
|
||||
ReducedModelOptimization::Results &optimizationResults);
|
||||
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
|
||||
)~";
|
||||
};
|
||||
|
||||
#endif // REDUCEDMODELEVALUATOR_HPP
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,417 @@
|
|||
#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
|
@ -1,813 +0,0 @@
|
|||
#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
|
|
@ -1,193 +0,0 @@
|
|||
#ifndef SIMULATIONHISTORYPLOTTER_HPP
|
||||
#define SIMULATIONHISTORYPLOTTER_HPP
|
||||
|
||||
#include "simulation_structs.hpp"
|
||||
#include "simulationmesh.hpp"
|
||||
#include "utilities.hpp"
|
||||
#include <algorithm>
|
||||
#include <matplot/matplot.h>
|
||||
|
||||
struct SimulationResultsReporter {
|
||||
using VertexType = VCGEdgeMesh::VertexType;
|
||||
using CoordType = VCGEdgeMesh::CoordType;
|
||||
|
||||
SimulationResultsReporter() {}
|
||||
|
||||
void writeStatistics(const SimulationResults &results,
|
||||
const std::string &reportFolderPath) {
|
||||
std::ofstream file;
|
||||
file.open(std::filesystem::path(reportFolderPath).append("results.txt").string());
|
||||
|
||||
const size_t numberOfSteps = results.history.numberOfSteps;
|
||||
file << "Number of steps " << numberOfSteps << "\n";
|
||||
|
||||
// file << "Force threshold used " << 1000 << "\n";
|
||||
|
||||
// assert(numberOfSteps == results.history.potentialEnergy.size() &&
|
||||
// numberOfSteps == results.history.residualForces.size());
|
||||
// Write kinetic energies
|
||||
const SimulationHistory &history = results.history;
|
||||
if (!history.kineticEnergy.empty()) {
|
||||
file << "Kinetic energies"
|
||||
<< "\n";
|
||||
for (size_t step = 0; step < numberOfSteps; step++) {
|
||||
file << history.kineticEnergy[step] << "\n";
|
||||
}
|
||||
file << "\n";
|
||||
}
|
||||
|
||||
if (!history.logResidualForces.empty()) {
|
||||
file << "Residual forces"
|
||||
<< "\n";
|
||||
for (size_t step = 0; step < numberOfSteps; step++) {
|
||||
file << history.logResidualForces[step] << "\n";
|
||||
}
|
||||
file << "\n";
|
||||
}
|
||||
|
||||
if (!history.potentialEnergies.empty()) {
|
||||
file << "Potential energies"
|
||||
<< "\n";
|
||||
for (size_t step = 0; step < numberOfSteps; step++) {
|
||||
file << history.potentialEnergies[step] << "\n";
|
||||
}
|
||||
file << "\n";
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void reportHistory(const SimulationHistory &history,
|
||||
const std::string &reportFolderPath,
|
||||
const std::string &graphSuffix = std::string())
|
||||
{
|
||||
const auto simulationResultPath = std::filesystem::path(reportFolderPath).append(history.label);
|
||||
std::filesystem::create_directories(simulationResultPath);
|
||||
createPlots(history, simulationResultPath.string(), graphSuffix);
|
||||
}
|
||||
|
||||
void reportResults(const std::vector<SimulationResults> &results,
|
||||
const std::string &reportFolderPath,
|
||||
const std::string &graphSuffix = std::string()) {
|
||||
if (results.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// std::filesystem::remove_all(debuggerFolder);
|
||||
std::filesystem::create_directory(reportFolderPath);
|
||||
for (const SimulationResults &simulationResult : results) {
|
||||
const auto simulationResultPath =
|
||||
std::filesystem::path(reportFolderPath)
|
||||
.append(simulationResult.getLabel());
|
||||
std::filesystem::create_directory(simulationResultPath.string());
|
||||
|
||||
createPlots(simulationResult.history, simulationResultPath.string(),
|
||||
graphSuffix);
|
||||
writeStatistics(simulationResult, simulationResultPath.string());
|
||||
}
|
||||
}
|
||||
static void createPlot(const std::string &xLabel,
|
||||
const std::string &yLabel,
|
||||
const std::vector<double> &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
|
|
@ -1,511 +0,0 @@
|
|||
#include "simulationmesh.hpp"
|
||||
//#include <wrap/nanoply/include/nanoplyWrapper.hpp>
|
||||
|
||||
SimulationMesh::SimulationMesh() {
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
|
||||
*this, std::string("Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(
|
||||
*this, std::string("Nodes"));
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(VCGEdgeMesh &mesh) {
|
||||
vcg::tri::MeshAssert<VCGEdgeMesh>::VertexNormalNormalized(mesh);
|
||||
|
||||
VCGEdgeMesh::copy(mesh);
|
||||
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
|
||||
*this, std::string("Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(*this,
|
||||
std::string("Nodes"));
|
||||
initializeNodes();
|
||||
initializeElements();
|
||||
}
|
||||
|
||||
SimulationMesh::~SimulationMesh() {
|
||||
vcg::tri::Allocator<SimulationMesh>::DeletePerEdgeAttribute<Element>(*this,
|
||||
elements);
|
||||
vcg::tri::Allocator<SimulationMesh>::DeletePerVertexAttribute<Node>(*this,
|
||||
nodes);
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(PatternGeometry &pattern) {
|
||||
vcg::tri::MeshAssert<PatternGeometry>::VertexNormalNormalized(pattern);
|
||||
VCGEdgeMesh::copy(pattern);
|
||||
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
|
||||
*this, std::string("Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(
|
||||
*this, std::string("Nodes"));
|
||||
initializeNodes();
|
||||
initializeElements();
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(SimulationMesh &m)
|
||||
{
|
||||
vcg::tri::MeshAssert<SimulationMesh>::VertexNormalNormalized(m);
|
||||
VCGEdgeMesh::copy(m);
|
||||
|
||||
elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(*this,
|
||||
std::string(
|
||||
"Elements"));
|
||||
nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(*this,
|
||||
std::string("Nodes"));
|
||||
initializeNodes();
|
||||
|
||||
for (size_t ei = 0; ei < EN(); ei++) {
|
||||
elements[ei] = m.elements[ei];
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
SimulationMesh::SimulationMesh(VCGTriMesh &triMesh)
|
||||
{
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGTriMesh>::MeshCopy(*this, triMesh);
|
||||
label = triMesh.getLabel();
|
||||
// eigenEdges = triMesh.getEigenEdges();
|
||||
// if (eigenEdges.rows() == 0) {
|
||||
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);
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
#ifndef SIMULATIONMESH_HPP
|
||||
#define SIMULATIONMESH_HPP
|
||||
|
||||
#include "edgemesh.hpp"
|
||||
#include "trianglepatterngeometry.hpp"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
//extern bool drawGlobal;
|
||||
struct Element;
|
||||
struct Node;
|
||||
using CrossSectionType = RectangularBeamDimensions;
|
||||
//using CrossSectionType = CylindricalBeamDimensions;
|
||||
|
||||
class SimulationMesh : public VCGEdgeMesh {
|
||||
private:
|
||||
void computeElementalProperties();
|
||||
void initializeElements();
|
||||
void initializeNodes();
|
||||
EdgePointer getReferenceElement(const VertexType &v);
|
||||
|
||||
const std::string plyPropertyBeamDimensionsID{"beam_dimensions"};
|
||||
const std::string plyPropertyBeamMaterialID{"beam_material"};
|
||||
|
||||
public:
|
||||
PerEdgeAttributeHandle<Element> elements;
|
||||
PerVertexAttributeHandle<Node> nodes;
|
||||
~SimulationMesh();
|
||||
SimulationMesh(PatternGeometry &pattern);
|
||||
SimulationMesh(ConstVCGEdgeMesh &edgeMesh);
|
||||
SimulationMesh(SimulationMesh &elementalMesh);
|
||||
SimulationMesh(VCGTriMesh &triMesh);
|
||||
void updateElementalLengths();
|
||||
void updateIncidentElements();
|
||||
|
||||
std::vector<VCGEdgeMesh::EdgePointer>
|
||||
getIncidentElements(const VCGEdgeMesh::VertexType &v);
|
||||
virtual bool load(const std::string &plyFilename);
|
||||
std::vector<CrossSectionType> getBeamDimensions();
|
||||
std::vector<ElementMaterial> getBeamMaterial();
|
||||
|
||||
double 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
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef SIMULATIONMODEL_HPP
|
||||
#define SIMULATIONMODEL_HPP
|
||||
|
||||
#include "simulation_structs.hpp"
|
||||
|
||||
class SimulationModel
|
||||
{
|
||||
public:
|
||||
virtual SimulationResults executeSimulation(const std::shared_ptr<SimulationJob> &simulationJob)
|
||||
= 0;
|
||||
};
|
||||
|
||||
#endif // SIMULATIONMODEL_HPP
|
|
@ -0,0 +1,25 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#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
|
|
@ -1,12 +1,13 @@
|
|||
#include "topologyenumerator.hpp"
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <boost/graph/biconnected_components.hpp>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <numeric>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
|
||||
const bool debugIsOn{false};
|
||||
const bool debugIsOn{true};
|
||||
const bool savePlyFiles{true};
|
||||
|
||||
// size_t binomialCoefficient(size_t n, size_t m) {
|
||||
|
@ -34,8 +35,7 @@ const bool savePlyFiles{true};
|
|||
// .string());
|
||||
//}
|
||||
|
||||
size_t TopologyEnumerator::getEdgeIndex(size_t ni0, size_t ni1) const
|
||||
{
|
||||
size_t TopologyEnumerator::getEdgeIndex(size_t ni0, size_t ni1) const {
|
||||
if (ni1 <= ni0) {
|
||||
std::swap(ni0, ni1);
|
||||
}
|
||||
|
@ -46,30 +46,35 @@ size_t TopologyEnumerator::getEdgeIndex(size_t ni0, size_t ni1) const
|
|||
|
||||
TopologyEnumerator::TopologyEnumerator() {}
|
||||
|
||||
void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reducedNumberOfNodesPerSlot,
|
||||
void TopologyEnumerator::computeValidPatterns(
|
||||
const std::vector<size_t>& reducedNumberOfNodesPerSlot,
|
||||
const std::string& desiredResultsPath,
|
||||
const int &numberOfDesiredEdges)
|
||||
{
|
||||
const int& numberOfDesiredEdges) {
|
||||
assert(reducedNumberOfNodesPerSlot.size() == 5);
|
||||
assert(reducedNumberOfNodesPerSlot[0] == 0 || reducedNumberOfNodesPerSlot[0] == 1);
|
||||
assert(reducedNumberOfNodesPerSlot[1] == 0 || reducedNumberOfNodesPerSlot[1] == 1);
|
||||
std::vector<size_t> numberOfNodesPerSlot{reducedNumberOfNodesPerSlot[0],
|
||||
reducedNumberOfNodesPerSlot[1],
|
||||
reducedNumberOfNodesPerSlot[1],
|
||||
reducedNumberOfNodesPerSlot[2],
|
||||
reducedNumberOfNodesPerSlot[3],
|
||||
reducedNumberOfNodesPerSlot[2],
|
||||
assert(reducedNumberOfNodesPerSlot[0] == 0 ||
|
||||
reducedNumberOfNodesPerSlot[0] == 1);
|
||||
assert(reducedNumberOfNodesPerSlot[1] == 0 ||
|
||||
reducedNumberOfNodesPerSlot[1] == 1);
|
||||
std::vector<size_t> numberOfNodesPerSlot{
|
||||
reducedNumberOfNodesPerSlot[0], reducedNumberOfNodesPerSlot[1],
|
||||
reducedNumberOfNodesPerSlot[1], reducedNumberOfNodesPerSlot[2],
|
||||
reducedNumberOfNodesPerSlot[3], reducedNumberOfNodesPerSlot[2],
|
||||
reducedNumberOfNodesPerSlot[4]};
|
||||
// Generate an edge mesh wih all possible edges
|
||||
numberOfNodes = std::accumulate(numberOfNodesPerSlot.begin(), numberOfNodesPerSlot.end(), 0);
|
||||
const size_t numberOfAllPossibleEdges = numberOfNodes * (numberOfNodes - 1) / 2;
|
||||
numberOfNodes = std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.end(), 0);
|
||||
const size_t numberOfAllPossibleEdges =
|
||||
numberOfNodes * (numberOfNodes - 1) / 2;
|
||||
|
||||
std::vector<vcg::Point2i> allPossibleEdges(numberOfAllPossibleEdges);
|
||||
const int& n = numberOfNodes;
|
||||
for (size_t edgeIndex = 0; edgeIndex < numberOfAllPossibleEdges; edgeIndex++) {
|
||||
const int ni0 = n - 2
|
||||
- std::floor(std::sqrt(-8 * edgeIndex + 4 * n * (n - 1) - 7) / 2.0 - 0.5);
|
||||
const int ni1 = edgeIndex + ni0 + 1 - n * (n - 1) / 2 + (n - ni0) * ((n - ni0) - 1) / 2;
|
||||
for (size_t edgeIndex = 0; edgeIndex < numberOfAllPossibleEdges;
|
||||
edgeIndex++) {
|
||||
const int ni0 =
|
||||
n - 2 -
|
||||
std::floor(std::sqrt(-8 * edgeIndex + 4 * n * (n - 1) - 7) / 2.0 - 0.5);
|
||||
const int ni1 =
|
||||
edgeIndex + ni0 + 1 - n * (n - 1) / 2 + (n - ni0) * ((n - ni0) - 1) / 2;
|
||||
allPossibleEdges[edgeIndex] = vcg::Point2i(ni0, ni1);
|
||||
}
|
||||
PatternGeometry patternGeometryAllEdges;
|
||||
|
@ -88,13 +93,15 @@ void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reduced
|
|||
std::string elemID;
|
||||
if (numberOfNodesPerSlotIndex == 0 || numberOfNodesPerSlotIndex == 1) {
|
||||
elemID = "v";
|
||||
} else if (numberOfNodesPerSlotIndex == 2 || numberOfNodesPerSlotIndex == 3) {
|
||||
} else if (numberOfNodesPerSlotIndex == 2 ||
|
||||
numberOfNodesPerSlotIndex == 3) {
|
||||
elemID = "e";
|
||||
} else {
|
||||
elemID = "c";
|
||||
}
|
||||
setupString += std::to_string(reducedNumberOfNodesPerSlot[numberOfNodesPerSlotIndex])
|
||||
+ elemID + "_";
|
||||
setupString +=
|
||||
std::to_string(reducedNumberOfNodesPerSlot[numberOfNodesPerSlotIndex]) +
|
||||
elemID + "_";
|
||||
}
|
||||
setupString += std::to_string(PatternGeometry().getFanSize()) + "fan";
|
||||
if (debugIsOn) {
|
||||
|
@ -105,55 +112,61 @@ void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reduced
|
|||
std::filesystem::create_directory(resultsPath);
|
||||
|
||||
if (debugIsOn) {
|
||||
patternGeometryAllEdges.save(
|
||||
std::filesystem::path(resultsPath).append("allPossibleEdges.ply").string());
|
||||
patternGeometryAllEdges.save(std::filesystem::path(resultsPath)
|
||||
.append("allPossibleEdges.ply")
|
||||
.string());
|
||||
}
|
||||
// statistics.numberOfPossibleEdges = numberOfAllPossibleEdges;
|
||||
|
||||
std::vector<vcg::Point2i> validEdges = getValidEdges(numberOfNodesPerSlot,
|
||||
resultsPath,
|
||||
patternGeometryAllEdges,
|
||||
std::vector<vcg::Point2i> validEdges =
|
||||
getValidEdges(numberOfNodesPerSlot, resultsPath, patternGeometryAllEdges,
|
||||
allPossibleEdges);
|
||||
PatternGeometry patternAllValidEdges;
|
||||
patternAllValidEdges.add(patternGeometryAllEdges.getVertices(), validEdges);
|
||||
patternAllValidEdges.add(patternGeometryAllEdges.computeVertices(),
|
||||
validEdges);
|
||||
if (debugIsOn) {
|
||||
// Export all valid edges in a ply
|
||||
patternAllValidEdges.save(
|
||||
std::filesystem::path(resultsPath).append("allValidEdges.ply").string());
|
||||
patternAllValidEdges.save(std::filesystem::path(resultsPath)
|
||||
.append("allValidEdges.ply")
|
||||
.string());
|
||||
}
|
||||
// statistics.numberOfValidEdges = validEdges.size();
|
||||
|
||||
// Find pairs of intersecting edges
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>> intersectingEdges
|
||||
= patternAllValidEdges.getIntersectingEdges(statistics.numberOfIntersectingEdgePairs);
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>
|
||||
intersectingEdges = patternAllValidEdges.getIntersectingEdges(
|
||||
statistics.numberOfIntersectingEdgePairs);
|
||||
if (debugIsOn) {
|
||||
auto intersectingEdgesPath = std::filesystem::path(resultsPath)
|
||||
.append("All_intersecting_edge_pairs");
|
||||
std::filesystem::create_directory(intersectingEdgesPath);
|
||||
// Export intersecting pairs in ply files
|
||||
for (auto mapIt = intersectingEdges.begin(); mapIt != intersectingEdges.end(); mapIt++) {
|
||||
for (auto setIt = mapIt->second.begin(); setIt != mapIt->second.end(); setIt++) {
|
||||
for (auto mapIt = intersectingEdges.begin();
|
||||
mapIt != intersectingEdges.end(); mapIt++) {
|
||||
for (auto setIt = mapIt->second.begin(); setIt != mapIt->second.end();
|
||||
setIt++) {
|
||||
PatternGeometry intersectingEdgePair;
|
||||
const size_t ei0 = mapIt->first;
|
||||
const size_t ei1 = *setIt;
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(
|
||||
intersectingEdgePair,
|
||||
patternGeometryAllEdges.getVertices()[validEdges[ei0][0]],
|
||||
patternGeometryAllEdges.getVertices()[validEdges[ei0][1]]);
|
||||
patternGeometryAllEdges.computeVertices()[validEdges[ei0][0]],
|
||||
patternGeometryAllEdges.computeVertices()[validEdges[ei0][1]]);
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(
|
||||
intersectingEdgePair,
|
||||
patternGeometryAllEdges.getVertices()[validEdges[ei1][0]],
|
||||
patternGeometryAllEdges.getVertices()[validEdges[ei1][1]]);
|
||||
patternGeometryAllEdges.computeVertices()[validEdges[ei1][0]],
|
||||
patternGeometryAllEdges.computeVertices()[validEdges[ei1][1]]);
|
||||
intersectingEdgePair.save(std::filesystem::path(intersectingEdgesPath)
|
||||
.append(std::to_string(mapIt->first) + "_"
|
||||
+ std::to_string(*setIt) + ".ply")
|
||||
.append(std::to_string(mapIt->first) +
|
||||
"_" + std::to_string(*setIt) +
|
||||
".ply")
|
||||
.string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::unordered_set<VertexIndex> interfaceNodes = patternGeometryAllEdges.getInterfaceNodes(
|
||||
numberOfNodesPerSlot);
|
||||
const std::unordered_set<VertexIndex> interfaceNodes =
|
||||
patternGeometryAllEdges.getInterfaceNodes(numberOfNodesPerSlot);
|
||||
|
||||
// assert(validEdges.size() == allPossibleEdges.size() -
|
||||
// coincideEdges.size() -
|
||||
|
@ -174,9 +187,10 @@ void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reduced
|
|||
// std::filesystem::path(resultsPath).append("patterns.patt"));
|
||||
// }
|
||||
if (numberOfDesiredEdges == -1) {
|
||||
for (size_t numberOfEdges = 2; numberOfEdges <= validEdges.size(); numberOfEdges++) {
|
||||
std::cout << "Computing " + setupString << " with " << numberOfEdges << " edges."
|
||||
<< std::endl;
|
||||
for (size_t numberOfEdges = 2; numberOfEdges <= validEdges.size();
|
||||
numberOfEdges++) {
|
||||
std::cout << "Computing " + setupString << " with " << numberOfEdges
|
||||
<< " edges." << std::endl;
|
||||
|
||||
auto perEdgeResultPath = std::filesystem::path(resultsPath)
|
||||
.append(std::to_string(numberOfEdges));
|
||||
|
@ -189,19 +203,16 @@ void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reduced
|
|||
// }
|
||||
}
|
||||
std::filesystem::create_directory(perEdgeResultPath);
|
||||
computeValidPatterns(numberOfNodesPerSlot,
|
||||
numberOfEdges,
|
||||
computeValidPatterns(numberOfNodesPerSlot, numberOfEdges,
|
||||
perEdgeResultPath,
|
||||
patternGeometryAllEdges.getVertices(),
|
||||
intersectingEdges,
|
||||
validEdges,
|
||||
interfaceNodes);
|
||||
patternGeometryAllEdges.computeVertices(),
|
||||
intersectingEdges, validEdges, interfaceNodes);
|
||||
statistics.print(setupString, perEdgeResultPath);
|
||||
statistics.reset();
|
||||
}
|
||||
} else {
|
||||
std::cout << "Computing " + setupString << " with " << numberOfDesiredEdges << " edges."
|
||||
<< std::endl;
|
||||
std::cout << "Computing " + setupString << " with " << numberOfDesiredEdges
|
||||
<< " edges." << std::endl;
|
||||
|
||||
auto perEdgeResultPath = std::filesystem::path(resultsPath)
|
||||
.append(std::to_string(numberOfDesiredEdges));
|
||||
|
@ -210,22 +221,19 @@ void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reduced
|
|||
std::filesystem::remove_all(perEdgeResultPath);
|
||||
}
|
||||
std::filesystem::create_directory(perEdgeResultPath);
|
||||
computeValidPatterns(numberOfNodesPerSlot,
|
||||
numberOfDesiredEdges,
|
||||
computeValidPatterns(numberOfNodesPerSlot, numberOfDesiredEdges,
|
||||
perEdgeResultPath,
|
||||
patternGeometryAllEdges.getVertices(),
|
||||
intersectingEdges,
|
||||
validEdges,
|
||||
interfaceNodes);
|
||||
patternGeometryAllEdges.computeVertices(),
|
||||
intersectingEdges, validEdges, interfaceNodes);
|
||||
statistics.print(setupString, perEdgeResultPath);
|
||||
}
|
||||
}
|
||||
|
||||
void TopologyEnumerator::computeEdgeNodes(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
void TopologyEnumerator::computeEdgeNodes(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
std::vector<size_t>& nodesEdge0,
|
||||
std::vector<size_t>& nodesEdge1,
|
||||
std::vector<size_t> &nodesEdge2)
|
||||
{
|
||||
std::vector<size_t>& nodesEdge2) {
|
||||
// Create vectors holding the node indices of each pattern node of each
|
||||
// triangle edge
|
||||
size_t nodeIndex = 0;
|
||||
|
@ -238,18 +246,21 @@ void TopologyEnumerator::computeEdgeNodes(const std::vector<size_t> &numberOfNod
|
|||
nodesEdge2.push_back(nodeIndex++);
|
||||
|
||||
if (numberOfNodesPerSlot[3] != 0) {
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[3]; edgeNodeIndex++) {
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[3];
|
||||
edgeNodeIndex++) {
|
||||
nodesEdge0.push_back(nodeIndex++);
|
||||
}
|
||||
}
|
||||
if (numberOfNodesPerSlot[4] != 0) {
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[4]; edgeNodeIndex++) {
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[4];
|
||||
edgeNodeIndex++) {
|
||||
nodesEdge1.push_back(nodeIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
if (numberOfNodesPerSlot[5] != 0) {
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[5]; edgeNodeIndex++) {
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[5];
|
||||
edgeNodeIndex++) {
|
||||
nodesEdge2.push_back(nodeIndex++);
|
||||
}
|
||||
}
|
||||
|
@ -265,8 +276,7 @@ void TopologyEnumerator::computeEdgeNodes(const std::vector<size_t> &numberOfNod
|
|||
}
|
||||
|
||||
std::unordered_set<size_t> TopologyEnumerator::computeCoincideEdges(
|
||||
const std::vector<size_t> &numberOfNodesPerSlot)
|
||||
{
|
||||
const std::vector<size_t>& numberOfNodesPerSlot) {
|
||||
/*
|
||||
* A coincide edge is defined as an edge connection between two nodes that lay
|
||||
* on a triangle edge and which have another node in between
|
||||
|
@ -279,12 +289,11 @@ std::unordered_set<size_t> TopologyEnumerator::computeCoincideEdges(
|
|||
std::vector<size_t> coincideEdges0 = getCoincideEdges(nodesEdge0);
|
||||
std::vector<size_t> coincideEdges1 = getCoincideEdges(nodesEdge1);
|
||||
std::vector<size_t> coincideEdges2 = getCoincideEdges(nodesEdge2);
|
||||
std::unordered_set<size_t> coincideEdges{coincideEdges0.begin(), coincideEdges0.end()};
|
||||
std::copy(coincideEdges1.begin(),
|
||||
coincideEdges1.end(),
|
||||
std::unordered_set<size_t> coincideEdges{coincideEdges0.begin(),
|
||||
coincideEdges0.end()};
|
||||
std::copy(coincideEdges1.begin(), coincideEdges1.end(),
|
||||
std::inserter(coincideEdges, coincideEdges.end()));
|
||||
std::copy(coincideEdges2.begin(),
|
||||
coincideEdges2.end(),
|
||||
std::copy(coincideEdges2.begin(), coincideEdges2.end(),
|
||||
std::inserter(coincideEdges, coincideEdges.end()));
|
||||
|
||||
if (numberOfNodesPerSlot[0] && numberOfNodesPerSlot[1]) {
|
||||
|
@ -300,8 +309,7 @@ std::unordered_set<size_t> TopologyEnumerator::computeCoincideEdges(
|
|||
}
|
||||
|
||||
std::unordered_set<size_t> TopologyEnumerator::computeDuplicateEdges(
|
||||
const std::vector<size_t> &numberOfNodesPerSlot)
|
||||
{
|
||||
const std::vector<size_t>& numberOfNodesPerSlot) {
|
||||
/*
|
||||
* A duplicate edges are all edges the "right" edge since due to rotational
|
||||
* symmetry "left" edge=="right" edge
|
||||
|
@ -312,7 +320,8 @@ std::unordered_set<size_t> TopologyEnumerator::computeDuplicateEdges(
|
|||
std::vector<size_t> nodesEdge2; // right edge
|
||||
computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2);
|
||||
if (numberOfNodesPerSlot[5]) {
|
||||
for (size_t edge2NodeIndex = 0; edge2NodeIndex < nodesEdge2.size() - 1; edge2NodeIndex++) {
|
||||
for (size_t edge2NodeIndex = 0; edge2NodeIndex < nodesEdge2.size() - 1;
|
||||
edge2NodeIndex++) {
|
||||
const size_t nodeIndex = nodesEdge2[edge2NodeIndex];
|
||||
const size_t nextNodeIndex = nodesEdge2[edge2NodeIndex + 1];
|
||||
duplicateEdges.insert(getEdgeIndex(nodeIndex, nextNodeIndex));
|
||||
|
@ -326,15 +335,17 @@ std::vector<vcg::Point2i> TopologyEnumerator::getValidEdges(
|
|||
const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const std::filesystem::path& resultsPath,
|
||||
const PatternGeometry& patternGeometryAllEdges,
|
||||
const std::vector<vcg::Point2i> &allPossibleEdges)
|
||||
{
|
||||
std::unordered_set<size_t> coincideEdges = computeCoincideEdges(numberOfNodesPerSlot);
|
||||
const std::vector<vcg::Point2i>& allPossibleEdges) {
|
||||
std::unordered_set<size_t> coincideEdges =
|
||||
computeCoincideEdges(numberOfNodesPerSlot);
|
||||
// Export each coincide edge into a ply file
|
||||
if (!coincideEdges.empty() && debugIsOn) {
|
||||
auto coincideEdgesPath = std::filesystem::path(resultsPath).append("Coincide_edges");
|
||||
auto coincideEdgesPath =
|
||||
std::filesystem::path(resultsPath).append("Coincide_edges");
|
||||
std::filesystem::create_directories(coincideEdgesPath);
|
||||
for (auto coincideEdgeIndex : coincideEdges) {
|
||||
PatternGeometry::EdgeType e = patternGeometryAllEdges.edge[coincideEdgeIndex];
|
||||
PatternGeometry::EdgeType e =
|
||||
patternGeometryAllEdges.edge[coincideEdgeIndex];
|
||||
PatternGeometry singleEdgeMesh;
|
||||
vcg::Point3d p0 = e.cP(0);
|
||||
vcg::Point3d p1 = e.cP(1);
|
||||
|
@ -345,34 +356,40 @@ std::vector<vcg::Point2i> TopologyEnumerator::getValidEdges(
|
|||
singleEdgeMesh.add(std::vector<vcg::Point2i>{vcg::Point2i{0, 1}});
|
||||
singleEdgeMesh.save(std::filesystem::path(coincideEdgesPath)
|
||||
.append(std::to_string(coincideEdgeIndex))
|
||||
.string()
|
||||
+ ".ply");
|
||||
.string() +
|
||||
".ply");
|
||||
}
|
||||
}
|
||||
statistics.numberOfCoincideEdges = coincideEdges.size();
|
||||
|
||||
// Compute duplicate edges
|
||||
std::unordered_set<size_t> duplicateEdges = computeDuplicateEdges(numberOfNodesPerSlot);
|
||||
std::unordered_set<size_t> duplicateEdges =
|
||||
computeDuplicateEdges(numberOfNodesPerSlot);
|
||||
if (!duplicateEdges.empty() && debugIsOn) {
|
||||
// Export duplicate edges in a single ply file
|
||||
auto duplicateEdgesPath = std::filesystem::path(resultsPath).append("duplicate");
|
||||
auto duplicateEdgesPath =
|
||||
std::filesystem::path(resultsPath).append("duplicate");
|
||||
std::filesystem::create_directory(duplicateEdgesPath);
|
||||
PatternGeometry patternDuplicateEdges;
|
||||
for (auto duplicateEdgeIndex : duplicateEdges) {
|
||||
PatternGeometry::EdgeType e = patternGeometryAllEdges.edge[duplicateEdgeIndex];
|
||||
PatternGeometry::EdgeType e =
|
||||
patternGeometryAllEdges.edge[duplicateEdgeIndex];
|
||||
vcg::Point3d p0 = e.cP(0);
|
||||
vcg::Point3d p1 = e.cP(1);
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(patternDuplicateEdges, p0, p1);
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(patternDuplicateEdges, p0,
|
||||
p1);
|
||||
}
|
||||
patternDuplicateEdges.save(
|
||||
std::filesystem::path(duplicateEdgesPath).append("duplicateEdges.ply").string());
|
||||
patternDuplicateEdges.save(std::filesystem::path(duplicateEdgesPath)
|
||||
.append("duplicateEdges.ply")
|
||||
.string());
|
||||
}
|
||||
statistics.numberOfDuplicateEdges = duplicateEdges.size();
|
||||
|
||||
// Create the set of all possible edges without coincide and duplicate edges
|
||||
std::vector<vcg::Point2i> validEdges;
|
||||
for (size_t edgeIndex = 0; edgeIndex < allPossibleEdges.size(); edgeIndex++) {
|
||||
if (coincideEdges.count(edgeIndex) == 0 && duplicateEdges.count(edgeIndex) == 0) {
|
||||
if (coincideEdges.count(edgeIndex) == 0 &&
|
||||
duplicateEdges.count(edgeIndex) == 0) {
|
||||
validEdges.push_back(allPossibleEdges[edgeIndex]);
|
||||
}
|
||||
}
|
||||
|
@ -382,15 +399,18 @@ std::vector<vcg::Point2i> TopologyEnumerator::getValidEdges(
|
|||
|
||||
void TopologyEnumerator::exportPattern(const std::filesystem::path& saveToPath,
|
||||
PatternGeometry& patternGeometry,
|
||||
const bool saveTilledPattern) const
|
||||
{
|
||||
const bool saveTilledPattern) const {
|
||||
const std::string patternName = patternGeometry.getLabel();
|
||||
std::filesystem::create_directory(saveToPath);
|
||||
patternGeometry.save(std::filesystem::path(saveToPath).append(patternName).string() + ".ply");
|
||||
patternGeometry.save(
|
||||
std::filesystem::path(saveToPath).append(patternName).string() + ".ply");
|
||||
if (saveTilledPattern) {
|
||||
PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(patternGeometry);
|
||||
tiledPatternGeometry.save(
|
||||
std::filesystem::path(saveToPath).append(patternName + "_tiled").string() + ".ply");
|
||||
PatternGeometry tiledPatternGeometry =
|
||||
PatternGeometry::createTile(patternGeometry);
|
||||
tiledPatternGeometry.save(std::filesystem::path(saveToPath)
|
||||
.append(patternName + "_tiled")
|
||||
.string() +
|
||||
".ply");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -399,10 +419,10 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
const size_t& numberOfDesiredEdges,
|
||||
const std::filesystem::path& resultsPath,
|
||||
const std::vector<vcg::Point3d>& allVertices,
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>> &intersectingEdges,
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>&
|
||||
intersectingEdges,
|
||||
const std::vector<vcg::Point2i>& validEdges,
|
||||
const std::unordered_set<VertexIndex> &interfaceNodes)
|
||||
{
|
||||
const std::unordered_set<VertexIndex>& interfaceNodes) {
|
||||
assert(numberOfNodesPerSlot.size() == 7);
|
||||
// Iterate over all patterns which have numberOfDesiredEdges edges from
|
||||
// from the validEdges Identify patterns that contain dangling edges
|
||||
|
@ -414,38 +434,45 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
assert(enoughValidEdgesExist);
|
||||
|
||||
// Create pattern result paths
|
||||
const auto validPatternsPath = std::filesystem::path(resultsPath).append("Valid");
|
||||
const bool validPathCreatedSuccesfully = std::filesystem::create_directories(validPatternsPath);
|
||||
assert(validPathCreatedSuccesfully && std::filesystem::exists(validPatternsPath));
|
||||
const auto validPatternsPath =
|
||||
std::filesystem::path(resultsPath).append("Valid");
|
||||
const bool validPathCreatedSuccesfully =
|
||||
std::filesystem::create_directories(validPatternsPath);
|
||||
assert(validPathCreatedSuccesfully &&
|
||||
std::filesystem::exists(validPatternsPath));
|
||||
// std::ofstream validPatternsFileStream;
|
||||
// validPatternsFileStream.open(
|
||||
// validPatternsPath.append("patterns.patt").string());
|
||||
const std::string compressedPatternsFilePath
|
||||
= std::filesystem::path(validPatternsPath).append("patterns.patt").string();
|
||||
const std::string compressedPatternsFilePath =
|
||||
std::filesystem::path(validPatternsPath).append("patterns.patt").string();
|
||||
PatternIO::PatternSet patternSet;
|
||||
patternSet.nodes = allVertices;
|
||||
const int patternSetBufferSize = 10000;
|
||||
|
||||
const size_t numberOfPatterns = PatternGeometry::binomialCoefficient(validEdges.size(),
|
||||
numberOfDesiredEdges);
|
||||
const size_t numberOfPatterns = PatternGeometry::binomialCoefficient(
|
||||
validEdges.size(), numberOfDesiredEdges);
|
||||
statistics.numberOfPatterns = numberOfPatterns;
|
||||
|
||||
// Initialize pattern binary representation
|
||||
std::string patternBinaryRepresentation;
|
||||
patternBinaryRepresentation = std::string(numberOfDesiredEdges, '1');
|
||||
patternBinaryRepresentation += std::string(validEdges.size() - numberOfDesiredEdges, '0');
|
||||
std::sort(patternBinaryRepresentation.begin(), patternBinaryRepresentation.end());
|
||||
patternBinaryRepresentation +=
|
||||
std::string(validEdges.size() - numberOfDesiredEdges, '0');
|
||||
std::sort(patternBinaryRepresentation.begin(),
|
||||
patternBinaryRepresentation.end());
|
||||
|
||||
/*TODO: Performance could be improved by changing the patternGeometry with
|
||||
* respect to the previous one. Maybe I could xor the binaryRepresentation
|
||||
* to the previous one.*/
|
||||
// std::string previousPatternBinaryRepresentation(validEdges.size(),'0');
|
||||
size_t patternIndex = 0;
|
||||
bool validPatternsExist = false;
|
||||
const bool exportTilledPattern = true;
|
||||
const bool saveCompressedFormat = false;
|
||||
constexpr bool exportTilledPattern = false;
|
||||
constexpr bool saveCompressedFormat = false;
|
||||
do {
|
||||
patternIndex++;
|
||||
const std::string patternName = std::to_string(patternIndex);
|
||||
const std::string patternName = std::to_string(numberOfDesiredEdges) + "_" +
|
||||
std::to_string(patternIndex);
|
||||
// std::cout << "Pattern name:" + patternBinaryRepresentation <<
|
||||
// std::endl; isValidPattern(patternBinaryRepresentation, validEdges,
|
||||
// numberOfDesiredEdges);
|
||||
|
@ -453,7 +480,8 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
// Compute the pattern edges from the binary representation
|
||||
std::vector<vcg::Point2i> patternEdges(numberOfDesiredEdges);
|
||||
size_t patternEdgeIndex = 0;
|
||||
for (size_t validEdgeIndex = 0; validEdgeIndex < patternBinaryRepresentation.size();
|
||||
for (size_t validEdgeIndex = 0;
|
||||
validEdgeIndex < patternBinaryRepresentation.size();
|
||||
validEdgeIndex++) {
|
||||
if (patternBinaryRepresentation[validEdgeIndex] == '1') {
|
||||
assert(patternEdgeIndex < numberOfDesiredEdges);
|
||||
|
@ -461,70 +489,124 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
}
|
||||
}
|
||||
|
||||
// DEBUG: Export only part of the pattern set
|
||||
// if (statistics.numberOfValidPatterns > 1e4) {
|
||||
// break;
|
||||
// }
|
||||
// const bool patternContainsCentroid =
|
||||
// std::find_if(patternEdges.begin(), patternEdges.end(),
|
||||
// [](const vcg::Point2i& edge) {
|
||||
// if (edge[0] == 0 || edge[1] == 0) {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }) != patternEdges.end();
|
||||
// if (!patternContainsCentroid) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
PatternGeometry patternGeometry;
|
||||
patternGeometry.add(allVertices, patternEdges);
|
||||
patternGeometry.setLabel(patternName);
|
||||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
// 1st example
|
||||
// const bool shouldBreak =
|
||||
// patternIndex == 1970494; // 398 const bool shouldBreak =
|
||||
// patternBinaryRepresentation == "10000010101110110";//13036 const
|
||||
// bool shouldBreak = patternBinaryRepresentation ==
|
||||
// "00010111000010100"; //2481 const bool shouldBreak =
|
||||
// patternBinaryRepresentation == "10000101100110010"; //12116 const
|
||||
// bool shouldBreak = patternBinaryRepresentation ==
|
||||
// "10010111000000110"; //13915
|
||||
// 2nd example
|
||||
// const bool shouldBreak = patternBinaryRepresentation ==
|
||||
// "00001011100010011"; //7_1203 const bool shouldBreak =
|
||||
// patternBinaryRepresentation == "00110001100100111"; //4865 const
|
||||
// bool shouldBreak = patternBinaryRepresentation ==
|
||||
// "00010000101000110"; //1380 const bool shouldBreak =
|
||||
// patternBinaryRepresentation == "00000010100010111"; //268
|
||||
// 3rd
|
||||
// const bool shouldBreak = patternBinaryRepresentation ==
|
||||
// "10011011100000010"; //14272 const bool shouldBreak =
|
||||
// patternBinaryRepresentation == "10000111100110110"; //11877 const
|
||||
// bool shouldBreak = patternBinaryRepresentation ==
|
||||
// "00001011100010011"; //1203 const bool shouldBreak =
|
||||
// patternBinaryRepresentation == "00010101000110000"; //12117
|
||||
|
||||
// const bool shouldBreak = patternBinaryRepresentation ==
|
||||
// "10000101100110100"; //12117
|
||||
// std::thread drawingThread([&]() {
|
||||
// if (shouldBreak) {
|
||||
// patternGeometry.registerForDrawing();
|
||||
// polyscope::show();
|
||||
// patternGeometry.unregister();
|
||||
// }
|
||||
// });
|
||||
#endif
|
||||
|
||||
// Check if pattern contains intersecting edges
|
||||
const bool isInterfaceConnected = patternGeometry.isInterfaceConnected(interfaceNodes);
|
||||
const bool isInterfaceConnected =
|
||||
patternGeometry.isInterfaceConnected(interfaceNodes);
|
||||
// Export the tiled ply file if it contains intersecting edges
|
||||
if (!isInterfaceConnected) {
|
||||
// create the tiled geometry of the pattern
|
||||
statistics.numberOfPatternViolatingInterfaceEnforcement++;
|
||||
if (debugIsOn) {
|
||||
if (savePlyFiles) {
|
||||
exportPattern(std::filesystem::path(resultsPath).append("InterfaceEnforcement"),
|
||||
patternGeometry,
|
||||
exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
continue; // should be uncommented in order to improve performance
|
||||
}
|
||||
}
|
||||
|
||||
// Check if pattern contains intersecting edges
|
||||
const bool patternContainsIntersectingEdges
|
||||
= patternGeometry.hasIntersectingEdges(patternBinaryRepresentation, intersectingEdges);
|
||||
// Export the tiled ply file if it contains intersecting edges
|
||||
if (patternContainsIntersectingEdges) {
|
||||
// create the tiled geometry of the pattern
|
||||
statistics.numberOfPatternsWithIntersectingEdges++;
|
||||
if (debugIsOn) {
|
||||
if (savePlyFiles) {
|
||||
exportPattern(std::filesystem::path(resultsPath).append("Intersecting"),
|
||||
patternGeometry,
|
||||
exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
continue; // should be uncommented in order to improve performance
|
||||
}
|
||||
}
|
||||
|
||||
// const bool shouldBreak = numberOfDesiredEdges == 4 && patternIndex == 53;
|
||||
const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold
|
||||
= patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 15);
|
||||
if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) {
|
||||
statistics.numberOfPatternsViolatingAngleThreshold++;
|
||||
if (debugIsOn /*|| savePlyFiles*/) {
|
||||
if (savePlyFiles) {
|
||||
exportPattern(std::filesystem::path(resultsPath)
|
||||
.append("ExceedingAngleThreshold"),
|
||||
patternGeometry,
|
||||
exportTilledPattern);
|
||||
exportPattern(
|
||||
std::filesystem::path(resultsPath).append("InterfaceEnforcement"),
|
||||
patternGeometry, exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const bool tiledPatternHasNodeWithValenceGreaterThanDesired
|
||||
= patternGeometry.hasValenceGreaterThan(numberOfNodesPerSlot, 6);
|
||||
// Check if pattern contains intersecting edges
|
||||
const bool patternContainsIntersectingEdges =
|
||||
patternGeometry.hasIntersectingEdges(patternBinaryRepresentation,
|
||||
intersectingEdges);
|
||||
// Export the tiled ply file if it contains intersecting edges
|
||||
if (patternContainsIntersectingEdges) {
|
||||
// create the tiled geometry of the pattern
|
||||
statistics.numberOfPatternsWithIntersectingEdges++;
|
||||
if (debugIsOn) {
|
||||
if (savePlyFiles) {
|
||||
exportPattern(
|
||||
std::filesystem::path(resultsPath).append("Intersecting"),
|
||||
patternGeometry, exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// const bool shouldBreak = numberOfDesiredEdges == 4 && patternIndex
|
||||
// == 53;
|
||||
const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold =
|
||||
patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 15);
|
||||
if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) {
|
||||
statistics.numberOfPatternsViolatingAngleThreshold++;
|
||||
if (debugIsOn /*|| savePlyFiles*/) {
|
||||
if (savePlyFiles) {
|
||||
exportPattern(std::filesystem::path(resultsPath)
|
||||
.append("ExceedingAngleThreshold"),
|
||||
patternGeometry, exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const bool tiledPatternHasNodeWithValenceGreaterThanDesired =
|
||||
patternGeometry.hasValenceGreaterThan(numberOfNodesPerSlot, 6);
|
||||
if (tiledPatternHasNodeWithValenceGreaterThanDesired) {
|
||||
statistics.numberOfPatternsViolatingValenceThreshold++;
|
||||
if (debugIsOn) {
|
||||
if (savePlyFiles) {
|
||||
auto highValencePath = std::filesystem::path(resultsPath)
|
||||
.append("HighValencePatterns");
|
||||
auto highValencePath =
|
||||
std::filesystem::path(resultsPath).append("HighValencePatterns");
|
||||
exportPattern(highValencePath, patternGeometry, exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
|
@ -536,35 +618,42 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
const bool tiledPatternHasDanglingEdges = patternGeometry.hasDanglingEdges(
|
||||
numberOfNodesPerSlot); // marks the nodes with valence>=1
|
||||
// Create the tiled geometry of the pattern
|
||||
const bool hasFloatingComponents = !patternGeometry.isFullyConnectedWhenFanned();
|
||||
const bool hasFloatingComponents =
|
||||
!patternGeometry.isFullyConnectedWhenFanned();
|
||||
|
||||
PatternGeometry fanPatternGeometry = PatternGeometry::createFan(patternGeometry);
|
||||
PatternGeometry fanPatternGeometry =
|
||||
PatternGeometry::createFan(patternGeometry);
|
||||
const int interfaceNodeVi = 3;
|
||||
std::vector<PatternGeometry::EdgeType*> connectedEdges;
|
||||
vcg::edge::VEStarVE(&fanPatternGeometry.vert[interfaceNodeVi], connectedEdges);
|
||||
vcg::edge::VEStarVE(&fanPatternGeometry.vert[interfaceNodeVi],
|
||||
connectedEdges);
|
||||
if (!connectedEdges.empty()) {
|
||||
for (int i = 1; i < 6; i++) {
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(fanPatternGeometry,
|
||||
interfaceNodeVi
|
||||
+ (i - 1) * patternGeometry.VN(),
|
||||
interfaceNodeVi
|
||||
+ i * patternGeometry.VN());
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(
|
||||
fanPatternGeometry,
|
||||
interfaceNodeVi + (i - 1) * patternGeometry.VN(),
|
||||
interfaceNodeVi + i * patternGeometry.VN());
|
||||
}
|
||||
}
|
||||
vcg::tri::Clean<PatternGeometry>::MergeCloseVertex(fanPatternGeometry, 0.0000005);
|
||||
vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(fanPatternGeometry);
|
||||
vcg::tri::Clean<PatternGeometry>::MergeCloseVertex(fanPatternGeometry,
|
||||
0.0000005);
|
||||
vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(
|
||||
fanPatternGeometry);
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(fanPatternGeometry);
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(fanPatternGeometry);
|
||||
// for (PatternGeometry::VertexType &v : tilledPatternGeometry.vert) {
|
||||
// for (PatternGeometry::VertexType &v : tilledPatternGeometry.vert)
|
||||
// {
|
||||
// std::vector<PatternGeometry::EdgeType *> connectedEdges;
|
||||
// vcg::edge::VEStarVE(&v, connectedEdges);
|
||||
// if (connectedEdges.size() == 1) {
|
||||
// vcg::tri::Allocator<PatternGeometry>::DeleteVertex(tilledPatternGeometry, v);
|
||||
// vcg::tri::Allocator<PatternGeometry>::DeleteVertex(tilledPatternGeometry,
|
||||
// v);
|
||||
// vcg::tri::Allocator<PatternGeometry>::DeleteEdge(tilledPatternGeometry,
|
||||
// *connectedEdges[0]);
|
||||
// }
|
||||
// }
|
||||
// // vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(tilledPatternGeometry);
|
||||
// //
|
||||
// vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(tilledPatternGeometry);
|
||||
// fanPatternGeometry.updateEigenEdgeAndVertices();
|
||||
|
||||
BoostGraph fanPatternGraph(fanPatternGeometry.VN());
|
||||
|
@ -581,21 +670,28 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
// std::cout << std::endl;
|
||||
|
||||
std::vector<vertex_t> articulationPoints;
|
||||
boost::articulation_points(fanPatternGraph, std::back_inserter(articulationPoints));
|
||||
boost::articulation_points(fanPatternGraph,
|
||||
std::back_inserter(articulationPoints));
|
||||
const bool hasArticulationPoints = !articulationPoints.empty();
|
||||
// if (!hasArticulationPoints && tiledPatternHasDanglingEdges) {
|
||||
// PatternGeometry tilledPatternGeometry = PatternGeometry::createTile(patternGeometry);
|
||||
// PatternGeometry tilledPatternGeometry =
|
||||
// PatternGeometry::createTile(patternGeometry);
|
||||
// tilledPatternGeometry.updateEigenEdgeAndVertices();
|
||||
// tilledPatternGeometry.registerForDrawing();
|
||||
// // ->addNodeColorQuantity("de_noAp_tilled", fanVertexColors)
|
||||
// // ->addNodeColorQuantity("de_noAp_tilled",
|
||||
// fanVertexColors)
|
||||
// // ->setEnabled(true);
|
||||
// polyscope::show();
|
||||
// tilledPatternGeometry.unregister();
|
||||
// }
|
||||
// if (hasArticulationPoints && !tiledPatternHasDanglingEdges/*&& !patternContainsIntersectingEdges
|
||||
// if (hasArticulationPoints && !tiledPatternHasDanglingEdges/*&&
|
||||
// !patternContainsIntersectingEdges
|
||||
// && !hasFloatingComponents
|
||||
// && !tiledPatternHasNodeWithValenceGreaterThanDesired
|
||||
// && !tiledPatternHasEdgesWithAngleSmallerThanThreshold*/) {
|
||||
// &&
|
||||
// !tiledPatternHasNodeWithValenceGreaterThanDesired
|
||||
// &&
|
||||
// !tiledPatternHasEdgesWithAngleSmallerThanThreshold*/)
|
||||
// {
|
||||
// for (PatternGeometry::VertexType &v : patternGeometry.vert) {
|
||||
// v.C() = vcg::Color4b::Yellow;
|
||||
// }
|
||||
|
@ -605,15 +701,20 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
// continue;
|
||||
// }
|
||||
// // std::cout << articulationPointVi << " ";
|
||||
// patternGeometry.vert[articulationPointVi].C() = vcg::Color4b::Red;
|
||||
// patternGeometry.vert[articulationPointVi].C() =
|
||||
// vcg::Color4b::Red;
|
||||
// }
|
||||
// PatternGeometry tilledPatternGeometry = PatternGeometry::createTile(patternGeometry);
|
||||
// PatternGeometry tilledPatternGeometry =
|
||||
// PatternGeometry::createTile(patternGeometry);
|
||||
// // std::cout << std::endl;
|
||||
// std::vector<glm::vec3> fanVertexColors(tilledPatternGeometry.VN(), glm::vec3(0, 0, 1));
|
||||
// for (const PatternGeometry::VertexType &v : tilledPatternGeometry.vert) {
|
||||
// const auto vColor = glm::vec3(v.cC()[0] / 255, v.cC()[1] / 255, v.cC()[2] / 255);
|
||||
// const auto vi = tilledPatternGeometry.getIndex(v);
|
||||
// fanVertexColors[vi] = vColor;
|
||||
// std::vector<glm::vec3>
|
||||
// fanVertexColors(tilledPatternGeometry.VN(), glm::vec3(0, 0,
|
||||
// 1)); for (const PatternGeometry::VertexType &v :
|
||||
// tilledPatternGeometry.vert) {
|
||||
// const auto vColor = glm::vec3(v.cC()[0] / 255, v.cC()[1] /
|
||||
// 255, v.cC()[2] / 255); const auto vi =
|
||||
// tilledPatternGeometry.getIndex(v); fanVertexColors[vi] =
|
||||
// vColor;
|
||||
// }
|
||||
// tilledPatternGeometry.updateEigenEdgeAndVertices();
|
||||
// tilledPatternGeometry.registerForDrawing()
|
||||
|
@ -630,8 +731,10 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
statistics.numberOfPatternsWithADanglingEdgeOrNode++;
|
||||
if (debugIsOn) {
|
||||
if (savePlyFiles) {
|
||||
auto danglingEdgesPath = std::filesystem::path(resultsPath).append("Dangling");
|
||||
exportPattern(danglingEdgesPath, patternGeometry, exportTilledPattern);
|
||||
auto danglingEdgesPath =
|
||||
std::filesystem::path(resultsPath).append("Dangling");
|
||||
exportPattern(danglingEdgesPath, patternGeometry,
|
||||
exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
|
@ -642,22 +745,23 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
statistics.numberOfPatternsWithMoreThanASingleCC++;
|
||||
if (debugIsOn) {
|
||||
if (savePlyFiles) {
|
||||
auto moreThanOneCCPath = std::filesystem::path(resultsPath)
|
||||
.append("MoreThanOneCC");
|
||||
auto moreThanOneCCPath =
|
||||
std::filesystem::path(resultsPath).append("MoreThanOneCC");
|
||||
std::filesystem::create_directory(moreThanOneCCPath);
|
||||
patternGeometry.save(
|
||||
std::filesystem::path(moreThanOneCCPath).append(patternName).string()
|
||||
+ ".ply");
|
||||
patternGeometry.save(std::filesystem::path(moreThanOneCCPath)
|
||||
.append(patternName)
|
||||
.string() +
|
||||
".ply");
|
||||
PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(
|
||||
patternGeometry); // the marked nodes of hasDanglingEdges are
|
||||
|
||||
std::vector<std::pair<int, PatternGeometry::EdgePointer>> eCC;
|
||||
vcg::tri::Clean<PatternGeometry>::edgeMeshConnectedComponents(tiledPatternGeometry,
|
||||
eCC);
|
||||
vcg::tri::UpdateFlags<PatternGeometry>::EdgeClear(tiledPatternGeometry);
|
||||
vcg::tri::Clean<PatternGeometry>::edgeMeshConnectedComponents(
|
||||
tiledPatternGeometry, eCC);
|
||||
vcg::tri::UpdateFlags<PatternGeometry>::EdgeClear(
|
||||
tiledPatternGeometry);
|
||||
const size_t numberOfCC_edgeBased = eCC.size();
|
||||
std::sort(eCC.begin(),
|
||||
eCC.end(),
|
||||
std::sort(eCC.begin(), eCC.end(),
|
||||
[](const std::pair<int, PatternGeometry::EdgePointer>& a,
|
||||
const std::pair<int, PatternGeometry::EdgePointer>& b) {
|
||||
return a.first > b.first;
|
||||
|
@ -679,12 +783,10 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
stack.push(vei.E());
|
||||
tiledPatternGeometry
|
||||
.vert[tiledPatternGeometry.getIndex(vei.V1())]
|
||||
.C()
|
||||
= vcg::Color4b::Blue;
|
||||
.C() = vcg::Color4b::Blue;
|
||||
tiledPatternGeometry
|
||||
.vert[tiledPatternGeometry.getIndex(vei.V0())]
|
||||
.C()
|
||||
= vcg::Color4b::Blue;
|
||||
.C() = vcg::Color4b::Blue;
|
||||
colorsRegistered++;
|
||||
}
|
||||
++vei;
|
||||
|
@ -697,8 +799,8 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
if (exportTilledPattern) {
|
||||
tiledPatternGeometry.save(std::filesystem::path(moreThanOneCCPath)
|
||||
.append(patternName + "_tiled")
|
||||
.string()
|
||||
+ ".ply");
|
||||
.string() +
|
||||
".ply");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -710,35 +812,40 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
statistics.numberOfPatternsWithArticulationPoints++;
|
||||
if (debugIsOn) {
|
||||
if (savePlyFiles) {
|
||||
auto articulationPointsPath = std::filesystem::path(resultsPath)
|
||||
.append("ArticulationPoints");
|
||||
exportPattern(articulationPointsPath, patternGeometry, exportTilledPattern);
|
||||
auto articulationPointsPath =
|
||||
std::filesystem::path(resultsPath).append("ArticulationPoints");
|
||||
exportPattern(articulationPointsPath, patternGeometry,
|
||||
exportTilledPattern);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const bool isValidPattern = !patternContainsIntersectingEdges
|
||||
&& isInterfaceConnected
|
||||
const bool isValidPattern =
|
||||
!patternContainsIntersectingEdges &&
|
||||
isInterfaceConnected
|
||||
/*&& !tiledPatternHasDanglingEdges*/
|
||||
&& !hasFloatingComponents && !hasArticulationPoints
|
||||
&& !tiledPatternHasNodeWithValenceGreaterThanDesired
|
||||
&& !tiledPatternHasEdgesWithAngleSmallerThanThreshold;
|
||||
&& !hasFloatingComponents && !hasArticulationPoints &&
|
||||
!tiledPatternHasNodeWithValenceGreaterThanDesired &&
|
||||
!tiledPatternHasEdgesWithAngleSmallerThanThreshold;
|
||||
// if (!hasArticulationPoints && !patternContainsIntersectingEdges
|
||||
// && !tiledPatternHasDanglingEdges && !hasFloatingComponents
|
||||
// && !tiledPatternHasNodeWithValenceGreaterThanDesired
|
||||
// && tiledPatternHasEdgesWithAngleSmallerThanThreshold && numberOfDesiredEdges > 4) {
|
||||
// std::cout << "Pattern found:" << patternName << std::endl;
|
||||
// && tiledPatternHasEdgesWithAngleSmallerThanThreshold &&
|
||||
// numberOfDesiredEdges > 4) { std::cout << "Pattern found:" <<
|
||||
// patternName << std::endl;
|
||||
// patternGeometry.registerForDrawing();
|
||||
// polyscope::show();
|
||||
// patternGeometry.unregister();
|
||||
// }
|
||||
if (isValidPattern) {
|
||||
// if(patternName=='2055'){
|
||||
// PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(
|
||||
// patternGeometry); // the marked nodes of hasDanglingEdges are
|
||||
// tiledPatternGeometry.registerForDrawing(std::array<double, 3>{0, 0, 1});
|
||||
// PatternGeometry tiledPatternGeometry =
|
||||
// PatternGeometry::createTile(
|
||||
// patternGeometry); // the marked nodes of
|
||||
// hasDanglingEdges are
|
||||
// tiledPatternGeometry.registerForDrawing(RGBColor{0, 0, 1});
|
||||
// polyscope::show();
|
||||
// tiledPatternGeometry.unregister();
|
||||
// }
|
||||
|
@ -762,6 +869,10 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
}
|
||||
}
|
||||
|
||||
// if (drawingThread.joinable()) {
|
||||
// drawingThread.join();
|
||||
// }
|
||||
|
||||
// assert(vcg_tiledPatternHasDangling == tiledPatternHasDanglingEdges);
|
||||
} while (std::next_permutation(patternBinaryRepresentation.begin(),
|
||||
patternBinaryRepresentation.end()));
|
||||
|
@ -778,16 +889,15 @@ void TopologyEnumerator::computeValidPatterns(
|
|||
}
|
||||
|
||||
std::vector<size_t> TopologyEnumerator::getCoincideEdges(
|
||||
const std::vector<size_t> &edgeNodeIndices) const
|
||||
{
|
||||
const std::vector<size_t>& edgeNodeIndices) const {
|
||||
std::vector<size_t> coincideEdges;
|
||||
if (edgeNodeIndices.size() < 3)
|
||||
return coincideEdges;
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < edgeNodeIndices.size() - 2; edgeNodeIndex++) {
|
||||
for (size_t edgeNodeIndex = 0; edgeNodeIndex < edgeNodeIndices.size() - 2;
|
||||
edgeNodeIndex++) {
|
||||
const size_t& firstNodeIndex = edgeNodeIndices[edgeNodeIndex];
|
||||
for (size_t secondEdgeNodeIndex = edgeNodeIndex + 2;
|
||||
secondEdgeNodeIndex < edgeNodeIndices.size();
|
||||
secondEdgeNodeIndex++) {
|
||||
secondEdgeNodeIndex < edgeNodeIndices.size(); secondEdgeNodeIndex++) {
|
||||
const size_t& secondNodeIndex = edgeNodeIndices[secondEdgeNodeIndex];
|
||||
coincideEdges.push_back(getEdgeIndex(firstNodeIndex, secondNodeIndex));
|
||||
}
|
||||
|
@ -795,9 +905,9 @@ std::vector<size_t> TopologyEnumerator::getCoincideEdges(
|
|||
return coincideEdges;
|
||||
}
|
||||
|
||||
bool TopologyEnumerator::isValidPattern(const std::string &patternBinaryRepresentation,
|
||||
bool TopologyEnumerator::isValidPattern(
|
||||
const std::string& patternBinaryRepresentation,
|
||||
const std::vector<vcg::Point2i>& validEdges,
|
||||
const size_t &numberOfDesiredEdges) const
|
||||
{
|
||||
const size_t& numberOfDesiredEdges) const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include "trianglepatterngeometry.hpp"
|
||||
#include "trianglepattterntopology.hpp"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <vcg/complex/algorithms/update/position.h>
|
||||
#include <vcg/simplex/edge/topology.h>
|
||||
#include <vcg/space/intersection2.h>
|
||||
#include <wrap/io_trimesh/export.h>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include "trianglepattterntopology.hpp"
|
||||
/* include the support for half edges */
|
||||
#include <vcg/complex/algorithms/update/halfedge_indexed.h>
|
||||
|
||||
|
@ -72,13 +72,17 @@ size_t PatternGeometry::computeTiledValence(
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t PatternGeometry::getFanSize() const { return fanSize; }
|
||||
size_t PatternGeometry::getFanSize() const {
|
||||
return fanSize;
|
||||
}
|
||||
|
||||
double PatternGeometry::getTriangleEdgeSize() const { return triangleEdgeSize; }
|
||||
double PatternGeometry::getTriangleEdgeSize() const {
|
||||
return triangleEdgeSize;
|
||||
}
|
||||
|
||||
PatternGeometry::PatternGeometry() {}
|
||||
|
||||
std::vector<vcg::Point3d> PatternGeometry::getVertices() const {
|
||||
std::vector<vcg::Point3d> PatternGeometry::computeVertices() const {
|
||||
std::vector<VCGEdgeMesh::CoordType> verts(VN());
|
||||
for (size_t vi = 0; vi < VN(); vi++) {
|
||||
verts[vi] = vert[vi].cP();
|
||||
|
@ -86,8 +90,7 @@ std::vector<vcg::Point3d> PatternGeometry::getVertices() const {
|
|||
return verts;
|
||||
}
|
||||
|
||||
PatternGeometry PatternGeometry::createTile(PatternGeometry &pattern)
|
||||
{
|
||||
PatternGeometry PatternGeometry::createTile(PatternGeometry& pattern) {
|
||||
const size_t fanSize = PatternGeometry().getFanSize();
|
||||
PatternGeometry fan(createFan(pattern));
|
||||
PatternGeometry tile(fan);
|
||||
|
@ -140,20 +143,24 @@ PatternGeometry PatternGeometry::createFan(PatternGeometry &pattern) {
|
|||
return fan;
|
||||
}
|
||||
|
||||
void PatternGeometry::updateBaseTriangle() {
|
||||
baseTriangle = computeBaseTriangle();
|
||||
}
|
||||
|
||||
PatternGeometry::PatternGeometry(PatternGeometry& other) {
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::MeshCopy(*this, other);
|
||||
this->vertices = other.getVertices();
|
||||
this->vertices = other.computeVertices();
|
||||
baseTriangle = other.getBaseTriangle();
|
||||
baseTriangleHeight = computeBaseTriangleHeight();
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(*this);
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(*this);
|
||||
}
|
||||
|
||||
bool PatternGeometry::load(const std::filesystem::__cxx11::path &meshFilePath)
|
||||
{
|
||||
bool PatternGeometry::load(const std::filesystem::__cxx11::path& meshFilePath) {
|
||||
if (!VCGEdgeMesh::load(meshFilePath)) {
|
||||
return false;
|
||||
}
|
||||
addNormals();
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(*this);
|
||||
baseTriangleHeight = computeBaseTriangleHeight();
|
||||
baseTriangle = computeBaseTriangle();
|
||||
|
@ -165,7 +172,7 @@ bool PatternGeometry::load(const std::filesystem::__cxx11::path &meshFilePath)
|
|||
void PatternGeometry::add(const std::vector<vcg::Point3d>& vertices) {
|
||||
this->vertices = vertices;
|
||||
std::for_each(vertices.begin(), vertices.end(), [&](const vcg::Point3d& p) {
|
||||
vcg::tri::Allocator<PatternGeometry>::AddVertex(*this, p);
|
||||
vcg::tri::Allocator<PatternGeometry>::AddVertex(*this, p, DefaultNormal);
|
||||
});
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(*this);
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(*this);
|
||||
|
@ -182,8 +189,7 @@ void PatternGeometry::add(const std::vector<vcg::Point2i> &edges) {
|
|||
}
|
||||
|
||||
void PatternGeometry::add(const std::vector<vcg::Point3d>& vertices,
|
||||
const std::vector<vcg::Point2i> &edges)
|
||||
{
|
||||
const std::vector<vcg::Point2i>& edges) {
|
||||
add(vertices);
|
||||
add(edges);
|
||||
updateEigenEdgeAndVertices();
|
||||
|
@ -201,9 +207,9 @@ void PatternGeometry::add(const std::vector<size_t> &numberOfNodesPerSlot,
|
|||
}
|
||||
|
||||
std::vector<vcg::Point3d> PatternGeometry::constructVertexVector(
|
||||
const std::vector<size_t> &numberOfNodesPerSlot, const size_t &fanSize,
|
||||
const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const size_t& fanSize,
|
||||
const double& triangleEdgeSize) {
|
||||
|
||||
std::vector<vcg::Point3d> vertices;
|
||||
const double centerAngle = 2 * M_PI / fanSize;
|
||||
const double triangleHeight =
|
||||
|
@ -236,7 +242,6 @@ std::vector<vcg::Point3d> PatternGeometry::constructVertexVector(
|
|||
const vcg::Point3d edgeVector0(triangleV1 - triangleV0);
|
||||
for (size_t vertexIndex = 0; vertexIndex < numberOfNodesPerSlot[3];
|
||||
vertexIndex++) {
|
||||
|
||||
// vertices[std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
// numberOfNodesPerSlot.begin() + 2, 0) +
|
||||
// vertexIndex] =
|
||||
|
@ -252,7 +257,6 @@ std::vector<vcg::Point3d> PatternGeometry::constructVertexVector(
|
|||
const vcg::Point3d edgeVector1(triangleV2 - triangleV1);
|
||||
for (size_t vertexIndex = 0; vertexIndex < numberOfNodesPerSlot[4];
|
||||
vertexIndex++) {
|
||||
|
||||
// vertices[std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
// numberOfNodesPerSlot.begin() + 3, 0) +
|
||||
// vertexIndex] =
|
||||
|
@ -305,32 +309,34 @@ void PatternGeometry::constructNodeToTiledValenceMap(
|
|||
}
|
||||
|
||||
std::vector<VectorType> PatternGeometry::getEdgeVectorsWithVertexAsOrigin(
|
||||
std::vector<EdgePointer> &edgePointers, const int &vi)
|
||||
{
|
||||
std::vector<EdgePointer>& edgePointers,
|
||||
const int& vi) {
|
||||
std::vector<VectorType> incidentElementsVectors(edgePointers.size());
|
||||
for (int incidentElementsIndex = 0; incidentElementsIndex < edgePointers.size();
|
||||
incidentElementsIndex++) {
|
||||
assert(vi == getIndex(edgePointers[incidentElementsIndex]->cV(0))
|
||||
|| vi == getIndex(edgePointers[incidentElementsIndex]->cV(1)));
|
||||
for (int incidentElementsIndex = 0;
|
||||
incidentElementsIndex < edgePointers.size(); incidentElementsIndex++) {
|
||||
assert(vi == getIndex(edgePointers[incidentElementsIndex]->cV(0)) ||
|
||||
vi == getIndex(edgePointers[incidentElementsIndex]->cV(1)));
|
||||
|
||||
incidentElementsVectors[incidentElementsIndex]
|
||||
= vi == getIndex(edgePointers[incidentElementsIndex]->cV(0))
|
||||
? edgePointers[incidentElementsIndex]->cP(1)
|
||||
- edgePointers[incidentElementsIndex]->cP(0)
|
||||
: edgePointers[incidentElementsIndex]->cP(0)
|
||||
- edgePointers[incidentElementsIndex]->cP(1);
|
||||
incidentElementsVectors[incidentElementsIndex] =
|
||||
vi == getIndex(edgePointers[incidentElementsIndex]->cV(0))
|
||||
? edgePointers[incidentElementsIndex]->cP(1) -
|
||||
edgePointers[incidentElementsIndex]->cP(0)
|
||||
: edgePointers[incidentElementsIndex]->cP(0) -
|
||||
edgePointers[incidentElementsIndex]->cP(1);
|
||||
}
|
||||
|
||||
return incidentElementsVectors;
|
||||
}
|
||||
|
||||
bool PatternGeometry::hasAngleSmallerThanThreshold(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
const double &angleThreshold_degrees)
|
||||
{
|
||||
bool PatternGeometry::hasAngleSmallerThanThreshold(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const double& angleThreshold_degrees,
|
||||
const bool shouldBreak) {
|
||||
assert(numberOfNodesPerSlot.size() == 7);
|
||||
// Initialize helping structs
|
||||
if (nodeToSlotMap.empty()) {
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap);
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot,
|
||||
nodeToSlotMap);
|
||||
}
|
||||
if (correspondingNode.empty()) {
|
||||
constructCorrespondingNodeMap(numberOfNodesPerSlot);
|
||||
|
@ -341,11 +347,13 @@ bool PatternGeometry::hasAngleSmallerThanThreshold(const std::vector<size_t> &nu
|
|||
// const double theta2 = vcg::math::ToDeg(vcg::Point2d(0, 1).Angle());
|
||||
// const double theta3 = vcg::math::ToDeg(vcg::Point2d(-1, 1).Angle());
|
||||
// const double theta4 = vcg::math::ToDeg(vcg::Point2d(-1, 0).Angle());
|
||||
// const double theta5 = vcg::math::ToDeg(vcg::Point2d(-1, -1).Angle() + 2 * M_PI);
|
||||
// const double theta6 = vcg::math::ToDeg(vcg::Point2d(0, -1).Angle() + 2 * M_PI);
|
||||
// const double theta7 = vcg::math::ToDeg(vcg::Point2d(1, -1).Angle() + 2 * M_PI);
|
||||
// const double theta5 = vcg::math::ToDeg(vcg::Point2d(-1, -1).Angle() + 2
|
||||
// * M_PI); const double theta6 = vcg::math::ToDeg(vcg::Point2d(0,
|
||||
// -1).Angle() + 2 * M_PI); const double theta7 =
|
||||
// vcg::math::ToDeg(vcg::Point2d(1, -1).Angle() + 2 * M_PI);
|
||||
|
||||
// std::set<double> test{theta0, theta1, theta2, theta3, theta4, theta5, theta6, theta7};
|
||||
// std::set<double> test{theta0, theta1, theta2, theta3, theta4, theta5,
|
||||
// theta6, theta7};
|
||||
|
||||
bool hasAngleSmallerThan = false;
|
||||
// find tiled incident edges for each node
|
||||
|
@ -358,112 +366,152 @@ bool PatternGeometry::hasAngleSmallerThanThreshold(const std::vector<size_t> &nu
|
|||
if (numberOfIncidentEdges == 0) {
|
||||
continue;
|
||||
}
|
||||
std::vector<VectorType> incidentEdgeVectors
|
||||
= getEdgeVectorsWithVertexAsOrigin(incidentElementPointers, vi);
|
||||
std::vector<VectorType> incidentEdgeVectors =
|
||||
getEdgeVectorsWithVertexAsOrigin(incidentElementPointers, vi);
|
||||
|
||||
std::vector<VectorType> tiledIncidentVectors = incidentEdgeVectors;
|
||||
const size_t slotIndex = nodeToSlotMap[vi];
|
||||
if (slotIndex == 2) {
|
||||
//NOTE:I assume that base triangle slots 1,2(bottom triangle nodes) are not used
|
||||
std::cerr
|
||||
<< "Slot of bottom base triangle nodes detected.This case is not handled.Exiting.."
|
||||
// NOTE:I assume that base triangle slots 1,2(bottom triangle nodes) are
|
||||
// not used
|
||||
std::cerr << "Slot of bottom base triangle nodes detected.This case is "
|
||||
"not handled.Exiting.."
|
||||
<< std::endl;
|
||||
std::terminate();
|
||||
} else if (slotIndex == 3 || slotIndex == 5) {
|
||||
// NOTE: I don't need to check both triangle edges
|
||||
std::vector<PatternGeometry::EdgePointer> correspondingVertexIncidentElementPointers;
|
||||
std::vector<PatternGeometry::EdgePointer>
|
||||
correspondingVertexIncidentElementPointers;
|
||||
vcg::edge::VEStarVE(&vert[correspondingNode[vi]],
|
||||
correspondingVertexIncidentElementPointers);
|
||||
std::vector<VectorType> correspondingVertexIncidentVectors
|
||||
= getEdgeVectorsWithVertexAsOrigin(correspondingVertexIncidentElementPointers,
|
||||
std::vector<VectorType> correspondingVertexIncidentVectors =
|
||||
getEdgeVectorsWithVertexAsOrigin(
|
||||
correspondingVertexIncidentElementPointers,
|
||||
correspondingNode[vi]);
|
||||
// const CoordType &correspondingVertexPosition = vert[correspondingNode[vi]].cP();
|
||||
// const CoordType &correspondingVertexPosition =
|
||||
// vert[correspondingNode[vi]].cP();
|
||||
vcg::Matrix33d R;
|
||||
if (slotIndex == 3) {
|
||||
R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1), vcg::math::ToRad(-360.0 / fanSize));
|
||||
R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1),
|
||||
vcg::math::ToRad(-360.0 / fanSize));
|
||||
} else {
|
||||
R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1), vcg::math::ToRad(360.0 / fanSize));
|
||||
R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1),
|
||||
vcg::math::ToRad(360.0 / fanSize));
|
||||
}
|
||||
// const CoordType &correspondingVertexPosition_rotated = vert[vi].cP();
|
||||
std::transform(
|
||||
correspondingVertexIncidentVectors.begin(),
|
||||
// const CoordType &correspondingVertexPosition_rotated =
|
||||
// vert[vi].cP();
|
||||
std::transform(correspondingVertexIncidentVectors.begin(),
|
||||
correspondingVertexIncidentVectors.end(),
|
||||
correspondingVertexIncidentVectors.begin(),
|
||||
[&](const VectorType& v) {
|
||||
// CoordType rotatedTarget = v * R;
|
||||
// v = rotatedTarget - correspondingVertexPosition_rotated;
|
||||
// CoordType rotatedTarget
|
||||
// = v * R; v =
|
||||
// rotatedTarget -
|
||||
// correspondingVertexPosition_rotated;
|
||||
return R * v;
|
||||
});
|
||||
tiledIncidentVectors.insert(tiledIncidentVectors.end(),
|
||||
correspondingVertexIncidentVectors.begin(),
|
||||
correspondingVertexIncidentVectors.end());
|
||||
} else if (slotIndex == 4) {
|
||||
std::vector<VectorType> reversedIncidentElementVectors(incidentEdgeVectors.size());
|
||||
std::transform(incidentEdgeVectors.begin(),
|
||||
incidentEdgeVectors.end(),
|
||||
std::vector<VectorType> reversedIncidentElementVectors(
|
||||
incidentEdgeVectors.size());
|
||||
std::transform(incidentEdgeVectors.begin(), incidentEdgeVectors.end(),
|
||||
reversedIncidentElementVectors.begin(),
|
||||
[&](const VectorType& v) { return -v; });
|
||||
//NOTE: for checking the angles not all opposite incident element vectors are needed but rather the two "extreme" ones of slot 4
|
||||
//here I simply add them all
|
||||
// NOTE: for checking the angles not all opposite incident element vectors
|
||||
// are needed but rather the two "extreme" ones of slot 4 here I simply
|
||||
// add them all
|
||||
tiledIncidentVectors.insert(tiledIncidentVectors.end(),
|
||||
reversedIncidentElementVectors.begin(),
|
||||
reversedIncidentElementVectors.end());
|
||||
}
|
||||
// if (shouldBreak) {
|
||||
// std::vector<std::array<double, 3>> edgePoints;
|
||||
// for (int tiledVectorIndex = 0; tiledVectorIndex < tiledIncidentVectors.size();
|
||||
// for (int tiledVectorIndex = 0;
|
||||
// tiledVectorIndex < tiledIncidentVectors.size();
|
||||
// tiledVectorIndex++) {
|
||||
// edgePoints.push_back(
|
||||
// std::array<double, 3>{vert[vi].cP()[0], vert[vi].cP()[1], vert[vi].cP()[2]});
|
||||
// edgePoints.push_back(
|
||||
// std::array<double, 3>{(vert[vi].cP() + tiledIncidentVectors[tiledVectorIndex])[0],
|
||||
// (vert[vi].cP() + tiledIncidentVectors[tiledVectorIndex])[1],
|
||||
// (vert[vi].cP() + tiledIncidentVectors[tiledVectorIndex])[2]});
|
||||
// edgePoints.push_back(std::array<double, 3>{
|
||||
// vert[vi].cP()[0], vert[vi].cP()[1], vert[vi].cP()[2]});
|
||||
// edgePoints.push_back(std::array<double, 3>{
|
||||
// (vert[vi].cP() +
|
||||
// tiledIncidentVectors[tiledVectorIndex])[0], (vert[vi].cP()
|
||||
// + tiledIncidentVectors[tiledVectorIndex])[1],
|
||||
// (vert[vi].cP() +
|
||||
// tiledIncidentVectors[tiledVectorIndex])[2]});
|
||||
// }
|
||||
// polyscope::registerCurveNetworkLine("temp", edgePoints);
|
||||
// polyscope::init();
|
||||
// polyscope::registerCurveNetworkLine("vi:" + std::to_string(vi),
|
||||
// edgePoints);
|
||||
|
||||
// polyscope::show();
|
||||
// polyscope::removeStructure("vi:" + std::to_string(vi));
|
||||
// }
|
||||
|
||||
if (tiledIncidentVectors.size() == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<double> thetaAnglesOfIncidentVectors(tiledIncidentVectors.size());
|
||||
std::transform(tiledIncidentVectors.begin(),
|
||||
tiledIncidentVectors.end(),
|
||||
std::vector<double> thetaAnglesOfIncidentVectors(
|
||||
tiledIncidentVectors.size());
|
||||
std::transform(
|
||||
tiledIncidentVectors.begin(), tiledIncidentVectors.end(),
|
||||
thetaAnglesOfIncidentVectors.begin(),
|
||||
[](const VectorType& v) { return vcg::Point2d(v[0], v[1]).Angle(); });
|
||||
// sort them using theta angles
|
||||
std::sort(thetaAnglesOfIncidentVectors.begin(), thetaAnglesOfIncidentVectors.end());
|
||||
std::sort(thetaAnglesOfIncidentVectors.begin(),
|
||||
thetaAnglesOfIncidentVectors.end());
|
||||
|
||||
//find nodes that contain incident edges with relative angles less than the threshold
|
||||
// std::vector<double> angles_theta(thetaAnglesOfIncidentVectors);
|
||||
// for (double &theta_rad : angles_theta) {
|
||||
// theta_rad = vcg::math::ToDeg(theta_rad);
|
||||
// }
|
||||
|
||||
// find nodes that contain incident edges with relative angles less than the
|
||||
// threshold
|
||||
const double angleThreshold_rad = vcg::math::ToRad(angleThreshold_degrees);
|
||||
for (int thetaAngleIndex = 1; thetaAngleIndex < thetaAnglesOfIncidentVectors.size();
|
||||
for (int thetaAngleIndex = 0;
|
||||
thetaAngleIndex < thetaAnglesOfIncidentVectors.size();
|
||||
thetaAngleIndex++) {
|
||||
const double absAngleDifference = std::abs(
|
||||
thetaAnglesOfIncidentVectors[thetaAngleIndex]
|
||||
- thetaAnglesOfIncidentVectors[thetaAngleIndex - 1]);
|
||||
const auto& va_theta =
|
||||
thetaAnglesOfIncidentVectors[(thetaAngleIndex + 1) %
|
||||
thetaAnglesOfIncidentVectors.size()];
|
||||
const auto& vb_theta = thetaAnglesOfIncidentVectors[thetaAngleIndex];
|
||||
// const auto &va
|
||||
// = tiledIncidentVectors[(thetaAngleIndex + 1) %
|
||||
// thetaAnglesOfIncidentVectors.size()];
|
||||
// const auto &vb = tiledIncidentVectors[thetaAngleIndex];
|
||||
const double absAngleDifference = std::abs(va_theta - vb_theta);
|
||||
// const double debug_difDegOtherway = vcg::math::ToDeg(
|
||||
// std::acos((va * vb) / (va.Norm() * vb.Norm())));
|
||||
// const double debug_diffDeg =
|
||||
// vcg::math::ToDeg(absAngleDifference);
|
||||
if (absAngleDifference < angleThreshold_rad
|
||||
/*&& absAngleDifference > vcg::math::ToRad(0.01)*/) {
|
||||
// std::cout << "Found angDiff:" << absAngleDifference << std::endl;
|
||||
// vert[vi].C() = vcg::Color4b::Magenta;
|
||||
// std::cout << "Found angDiff:" << absAngleDifference <<
|
||||
// std::endl; vert[vi].C() = vcg::Color4b::Magenta;
|
||||
// hasAngleSmallerThan = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const double firstLastPairAngleDiff = std::abs(
|
||||
thetaAnglesOfIncidentVectors[0]
|
||||
- thetaAnglesOfIncidentVectors[thetaAnglesOfIncidentVectors.size() - 1]);
|
||||
if (firstLastPairAngleDiff < angleThreshold_rad && firstLastPairAngleDiff > 0.01) {
|
||||
thetaAnglesOfIncidentVectors[0] -
|
||||
thetaAnglesOfIncidentVectors[thetaAnglesOfIncidentVectors.size() - 1]);
|
||||
if (firstLastPairAngleDiff < angleThreshold_rad &&
|
||||
firstLastPairAngleDiff > 0.01) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PatternGeometry::hasValenceGreaterThan(const std::vector<size_t> &numberOfNodesPerSlot,
|
||||
const size_t &valenceThreshold)
|
||||
{
|
||||
bool PatternGeometry::hasValenceGreaterThan(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const size_t& valenceThreshold) {
|
||||
// Initialize helping structs
|
||||
if (nodeToSlotMap.empty()) {
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap);
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot,
|
||||
nodeToSlotMap);
|
||||
}
|
||||
if (correspondingNode.empty()) {
|
||||
constructCorrespondingNodeMap(numberOfNodesPerSlot);
|
||||
|
@ -488,7 +536,8 @@ bool PatternGeometry::hasDanglingEdges(
|
|||
const std::vector<size_t>& numberOfNodesPerSlot) {
|
||||
// Initialize helping structs
|
||||
if (nodeToSlotMap.empty()) {
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap);
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot,
|
||||
nodeToSlotMap);
|
||||
}
|
||||
if (correspondingNode.empty()) {
|
||||
constructCorrespondingNodeMap(numberOfNodesPerSlot);
|
||||
|
@ -522,7 +571,6 @@ bool PatternGeometry::hasUntiledDanglingEdges() {
|
|||
const size_t nodeValence = connectedEdges.size();
|
||||
if (nodeValence == 1) {
|
||||
if (vert[vi].C().operator==(vcg::Color4b(vcg::Color4b::Red))) {
|
||||
|
||||
} else {
|
||||
vert[vi].C() = vcg::Color4b::Blue;
|
||||
}
|
||||
|
@ -534,10 +582,10 @@ bool PatternGeometry::hasUntiledDanglingEdges() {
|
|||
|
||||
// TODO: The function expects that the numberOfNodesPerSlot follows a specific
|
||||
// format and that the vertex container was populated in a particular order.
|
||||
void PatternGeometry::constructCorrespondingNodeMap(const std::vector<size_t> &numberOfNodesPerSlot)
|
||||
{
|
||||
assert(vn != 0 && !nodeToSlotMap.empty() && correspondingNode.empty()
|
||||
&& numberOfNodesPerSlot.size() == 7);
|
||||
void PatternGeometry::constructCorrespondingNodeMap(
|
||||
const std::vector<size_t>& numberOfNodesPerSlot) {
|
||||
assert(vn != 0 && !nodeToSlotMap.empty() && correspondingNode.empty() &&
|
||||
numberOfNodesPerSlot.size() == 7);
|
||||
|
||||
for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) {
|
||||
const size_t slotIndex = nodeToSlotMap[nodeIndex];
|
||||
|
@ -546,33 +594,32 @@ void PatternGeometry::constructCorrespondingNodeMap(const std::vector<size_t> &n
|
|||
} else if (slotIndex == 2) {
|
||||
correspondingNode[nodeIndex] = nodeIndex - 1;
|
||||
} else if (slotIndex == 3) {
|
||||
const size_t numberOfNodesBefore = nodeIndex
|
||||
- std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.begin() + 3,
|
||||
0);
|
||||
correspondingNode[nodeIndex] = std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.begin() + 6,
|
||||
0)
|
||||
- 1 - numberOfNodesBefore;
|
||||
const size_t numberOfNodesBefore =
|
||||
nodeIndex - std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.begin() + 3, 0);
|
||||
correspondingNode[nodeIndex] =
|
||||
std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.begin() + 6, 0) -
|
||||
1 - numberOfNodesBefore;
|
||||
} else if (slotIndex == 5) {
|
||||
const size_t numberOfNodesAfter = std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.begin() + 6,
|
||||
0)
|
||||
- 1 - nodeIndex;
|
||||
correspondingNode[nodeIndex] = numberOfNodesAfter
|
||||
+ std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
const size_t numberOfNodesAfter =
|
||||
std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.begin() + 6, 0) -
|
||||
1 - nodeIndex;
|
||||
correspondingNode[nodeIndex] =
|
||||
numberOfNodesAfter + std::accumulate(numberOfNodesPerSlot.begin(),
|
||||
numberOfNodesPerSlot.begin() + 3,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PatternGeometry::isFullyConnectedWhenFanned()
|
||||
{
|
||||
bool PatternGeometry::isFullyConnectedWhenFanned() {
|
||||
assert(vn != 0 /* && !correspondingNode.empty()*/);
|
||||
// TrianglePatternGeometry copyOfPattern(*this);
|
||||
|
||||
// // If bottom interface nodes have a valence of zero there definetely more than
|
||||
// // If bottom interface nodes have a valence of zero there definetely more
|
||||
// than
|
||||
// // a single cc
|
||||
// bool bottomInterfaceIsConnected = false;
|
||||
// for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) {
|
||||
|
@ -597,7 +644,8 @@ bool PatternGeometry::isFullyConnectedWhenFanned()
|
|||
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(fanedPattern);
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(fanedPattern);
|
||||
std::vector<std::pair<int, PatternGeometry::EdgePointer>> eCC;
|
||||
vcg::tri::Clean<PatternGeometry>::edgeMeshConnectedComponents(fanedPattern, eCC);
|
||||
vcg::tri::Clean<PatternGeometry>::edgeMeshConnectedComponents(fanedPattern,
|
||||
eCC);
|
||||
|
||||
const bool sideInterfaceIsConnected = 1 == eCC.size();
|
||||
if (!sideInterfaceIsConnected) {
|
||||
|
@ -676,14 +724,15 @@ bool PatternGeometry::isFullyConnectedWhenFanned()
|
|||
|
||||
bool PatternGeometry::hasIntersectingEdges(
|
||||
const std::string& patternBinaryRepresentation,
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>
|
||||
&intersectingEdges) {
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>&
|
||||
intersectingEdges) {
|
||||
bool containsIntersectingEdges = false;
|
||||
for (size_t validEdgeIndex = 0;
|
||||
validEdgeIndex < patternBinaryRepresentation.size(); validEdgeIndex++) {
|
||||
if (patternBinaryRepresentation[validEdgeIndex] == '1'
|
||||
&& intersectingEdges.contains(validEdgeIndex)) {
|
||||
for (auto edgeIndexIt = intersectingEdges.find(validEdgeIndex)->second.begin();
|
||||
if (patternBinaryRepresentation[validEdgeIndex] == '1' &&
|
||||
intersectingEdges.contains(validEdgeIndex)) {
|
||||
for (auto edgeIndexIt =
|
||||
intersectingEdges.find(validEdgeIndex)->second.begin();
|
||||
edgeIndexIt != intersectingEdges.find(validEdgeIndex)->second.end();
|
||||
edgeIndexIt++) {
|
||||
if (patternBinaryRepresentation[*edgeIndexIt] == '1') {
|
||||
|
@ -753,16 +802,16 @@ PatternGeometry::getIntersectingEdges(
|
|||
return intersectingEdges;
|
||||
}
|
||||
|
||||
PatternGeometry::PatternGeometry(const std::string &filename,
|
||||
PatternGeometry::PatternGeometry(const std::filesystem::path& patternFilePath,
|
||||
bool addNormalsIfAbsent) {
|
||||
if (!std::filesystem::exists(std::filesystem::path(filename))) {
|
||||
if (!std::filesystem::exists(std::filesystem::path(patternFilePath))) {
|
||||
assert(false);
|
||||
std::cerr << "No flat pattern with name " << filename << std::endl;
|
||||
std::cerr << "No flat pattern with name " << patternFilePath << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!load(filename)) {
|
||||
if (!load(patternFilePath)) {
|
||||
assert(false);
|
||||
std::cerr << "File could not be loaded " << filename << std::endl;
|
||||
std::cerr << "File could not be loaded " << patternFilePath << std::endl;
|
||||
return;
|
||||
}
|
||||
if (addNormalsIfAbsent) {
|
||||
|
@ -776,34 +825,32 @@ PatternGeometry::PatternGeometry(const std::string &filename,
|
|||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
|
||||
double PatternGeometry::computeBaseTriangleHeight() const
|
||||
{
|
||||
double PatternGeometry::computeBaseTriangleHeight() const {
|
||||
return vcg::Distance(vert[0].cP(), vert[interfaceNodeIndex].cP());
|
||||
}
|
||||
|
||||
void PatternGeometry::deleteDanglingVertices()
|
||||
{
|
||||
void PatternGeometry::updateBaseTriangleHeight() {
|
||||
baseTriangleHeight = computeBaseTriangleHeight();
|
||||
}
|
||||
|
||||
void PatternGeometry::deleteDanglingVertices() {
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> pu;
|
||||
VCGEdgeMesh::deleteDanglingVertices(pu);
|
||||
if (!pu.remap.empty()) {
|
||||
interfaceNodeIndex
|
||||
= pu.remap[interfaceNodeIndex]; //TODO:Could this be automatically be determined?
|
||||
interfaceNodeIndex = pu.remap[interfaceNodeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
void PatternGeometry::deleteDanglingVertices(
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> &pu)
|
||||
{
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer>& pu) {
|
||||
VCGEdgeMesh::deleteDanglingVertices(pu);
|
||||
}
|
||||
|
||||
vcg::Triangle3<double> PatternGeometry::getBaseTriangle() const
|
||||
{
|
||||
vcg::Triangle3<double> PatternGeometry::getBaseTriangle() const {
|
||||
return baseTriangle;
|
||||
}
|
||||
|
||||
void PatternGeometry::addNormals()
|
||||
{
|
||||
void PatternGeometry::addNormals() {
|
||||
bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001;
|
||||
if (normalsAreAbsent) {
|
||||
for (auto& v : vert) {
|
||||
|
@ -812,16 +859,16 @@ void PatternGeometry::addNormals()
|
|||
}
|
||||
}
|
||||
|
||||
vcg::Triangle3<double> PatternGeometry::computeBaseTriangle() const
|
||||
{
|
||||
vcg::Triangle3<double> PatternGeometry::computeBaseTriangle() const {
|
||||
const double baseTriangleHeight = computeBaseTriangleHeight();
|
||||
double bottomEdgeHalfSize = baseTriangleHeight / std::tan(M_PI / 3);
|
||||
CoordType patternCoord0 = vert[0].cP();
|
||||
CoordType patternBottomRight = vert[interfaceNodeIndex].cP()
|
||||
+ CoordType(bottomEdgeHalfSize, 0, 0);
|
||||
CoordType patternBottomLeft = vert[interfaceNodeIndex].cP()
|
||||
- CoordType(bottomEdgeHalfSize, 0, 0);
|
||||
return vcg::Triangle3<double>(patternCoord0, patternBottomLeft, patternBottomRight);
|
||||
CoordType patternBottomRight =
|
||||
vert[interfaceNodeIndex].cP() + CoordType(bottomEdgeHalfSize, 0, 0);
|
||||
CoordType patternBottomLeft =
|
||||
vert[interfaceNodeIndex].cP() - CoordType(bottomEdgeHalfSize, 0, 0);
|
||||
return vcg::Triangle3<double>(patternCoord0, patternBottomLeft,
|
||||
patternBottomRight);
|
||||
}
|
||||
|
||||
PatternGeometry::PatternGeometry(
|
||||
|
@ -831,33 +878,37 @@ PatternGeometry::PatternGeometry(
|
|||
addNormals();
|
||||
baseTriangleHeight = computeBaseTriangleHeight();
|
||||
baseTriangle = computeBaseTriangle();
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(*this);
|
||||
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(*this);
|
||||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
|
||||
//TODO: refactor such that it takes as an input a single pattern and tiles into the desired faces without requiring the each face will contain a single pattern
|
||||
// TODO: refactor such that it takes as an input a single pattern and tiles into
|
||||
// the desired faces without requiring the each face will contain a single
|
||||
// pattern
|
||||
std::shared_ptr<PatternGeometry> 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>> &perPatternIndexToTiledPatternEdgeIndex)
|
||||
{
|
||||
std::vector<std::vector<size_t>>& perPatternIndexToTiledPatternEdgeIndex) {
|
||||
perPatternIndexToTiledPatternEdgeIndex.resize(patterns.size());
|
||||
std::shared_ptr<PatternGeometry> pTiledPattern(new PatternGeometry);
|
||||
std::vector<std::vector<int>> tileIntoEdgeToInterfaceVi(
|
||||
tileInto.EN()); //ith element contains all the interface nodes that lay on the ith edge of tileInto
|
||||
tileInto.EN()); // ith element contains all the interface nodes that lay
|
||||
// on the ith edge of tileInto
|
||||
// Compute the barycentric coords of the verts in the base triangle pattern
|
||||
std::vector<std::vector<CoordType>> barycentricCoordinates(patterns.size());
|
||||
for (size_t patternIndex = 0; patternIndex < patterns.size(); patternIndex++) {
|
||||
for (size_t patternIndex = 0; patternIndex < patterns.size();
|
||||
patternIndex++) {
|
||||
const PatternGeometry& pattern = patterns[patternIndex];
|
||||
const vcg::Triangle3<double>& baseTriangle = pattern.getBaseTriangle();
|
||||
barycentricCoordinates[patternIndex].resize(pattern.VN());
|
||||
for (int vi = 0; vi < pattern.VN(); vi++) {
|
||||
CoordType barycentricCoords_vi;
|
||||
vcg::InterpolationParameters<vcg::Triangle3<double>, double>(baseTriangle,
|
||||
pattern.vert[vi].cP(),
|
||||
barycentricCoords_vi);
|
||||
vcg::InterpolationParameters<vcg::Triangle3<double>, double>(
|
||||
baseTriangle, pattern.vert[vi].cP(), barycentricCoords_vi);
|
||||
barycentricCoordinates[patternIndex][vi] = barycentricCoords_vi;
|
||||
}
|
||||
}
|
||||
|
@ -866,8 +917,8 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
assert(vcg::tri::HasFEAdjacency(tileInto));
|
||||
assert(vcg::tri::HasFVAdjacency(tileInto));
|
||||
for (const VCGPolyMesh::FaceType& f : tileInto.face) {
|
||||
const int facePatternIndex = perSurfaceFacePatternIndices[tileInto.getIndex(f)];
|
||||
if (facePatternIndex == -1) {
|
||||
const int patternIndex = perSurfaceFacePatternIndices[tileInto.getIndex(f)];
|
||||
if (patternIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
CoordType centerOfFace(0, 0, 0);
|
||||
|
@ -875,29 +926,29 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
centerOfFace = centerOfFace + f.cP(vi);
|
||||
}
|
||||
centerOfFace /= f.VN();
|
||||
vcg::tri::Allocator<VCGTriMesh>::AddVertex(tileIntoEdgeMesh,
|
||||
centerOfFace,
|
||||
vcg::tri::Allocator<VCGTriMesh>::AddVertex(tileIntoEdgeMesh, centerOfFace,
|
||||
vcg::Color4b::Yellow);
|
||||
|
||||
std::vector<int> firstInFanConnectToNeighbor_vi(connectToNeighborsVi);
|
||||
for (int& vi : firstInFanConnectToNeighbor_vi) {
|
||||
vi += pTiledPattern->VN();
|
||||
}
|
||||
ConstPatternGeometry &pattern = patterns[facePatternIndex];
|
||||
ConstPatternGeometry& pattern = patterns[patternIndex];
|
||||
|
||||
for (size_t vi = 0; vi < f.VN(); vi++) {
|
||||
auto ep = f.FEp(vi);
|
||||
assert(vcg::tri::IsValidPointer(tileInto, ep));
|
||||
std::vector<vcg::Point3d> meshTrianglePoints{centerOfFace,
|
||||
f.cP(vi),
|
||||
vi + 1 == f.VN() ? f.cP(0) : f.cP(vi + 1)};
|
||||
// std::vector<vcg::Point3d> meshTrianglePoints{centerOfFace, ep->cP(0), ep->cP(1)};
|
||||
auto fit = vcg::tri::Allocator<VCGTriMesh>::AddFace(tileIntoEdgeMesh,
|
||||
meshTrianglePoints[0],
|
||||
meshTrianglePoints[1],
|
||||
std::vector<vcg::Point3d> meshTrianglePoints{
|
||||
centerOfFace, f.cP(vi), vi + 1 == f.VN() ? f.cP(0) : f.cP(vi + 1)};
|
||||
// std::vector<vcg::Point3d> meshTrianglePoints{centerOfFace,
|
||||
// ep->cP(0), ep->cP(1)};
|
||||
auto fit = vcg::tri::Allocator<VCGTriMesh>::AddFace(
|
||||
tileIntoEdgeMesh, meshTrianglePoints[0], meshTrianglePoints[1],
|
||||
meshTrianglePoints[2]);
|
||||
// CoordType faceNormal = ((meshTrianglePoints[1] - meshTrianglePoints[0])
|
||||
// ^ (meshTrianglePoints[2] - meshTrianglePoints[0]))
|
||||
// CoordType faceNormal = ((meshTrianglePoints[1] -
|
||||
// meshTrianglePoints[0])
|
||||
// ^ (meshTrianglePoints[2] -
|
||||
// meshTrianglePoints[0]))
|
||||
// .Normalize();
|
||||
// TODO: in planar surfaces I should compute the face of triangle
|
||||
CoordType faceNormal = f.cN();
|
||||
|
@ -905,12 +956,19 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
fit->N() = faceNormal;
|
||||
PatternGeometry transformedPattern;
|
||||
transformedPattern.copy(pattern);
|
||||
//Transform the base triangle nodes to the mesh triangle using barycentric coords
|
||||
// pattern.registerForDrawing();
|
||||
// polyscope::show();
|
||||
// pattern.unregister();
|
||||
// Transform the base triangle nodes to the mesh triangle using
|
||||
// barycentric coords
|
||||
for (int vi = 0; vi < transformedPattern.VN(); vi++) {
|
||||
transformedPattern.vert[vi].P() = CoordType(
|
||||
meshTrianglePoints[0] * barycentricCoordinates[facePatternIndex][vi][0]
|
||||
+ meshTrianglePoints[1] * barycentricCoordinates[facePatternIndex][vi][1]
|
||||
+ meshTrianglePoints[2] * barycentricCoordinates[facePatternIndex][vi][2]);
|
||||
transformedPattern.vert[vi].P() =
|
||||
CoordType(meshTrianglePoints[0] *
|
||||
barycentricCoordinates[patternIndex][vi][0] +
|
||||
meshTrianglePoints[1] *
|
||||
barycentricCoordinates[patternIndex][vi][1] +
|
||||
meshTrianglePoints[2] *
|
||||
barycentricCoordinates[patternIndex][vi][2]);
|
||||
}
|
||||
|
||||
for (VertexType& v : transformedPattern.vert) {
|
||||
|
@ -918,14 +976,19 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
}
|
||||
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::Remap remap;
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::Mesh(*pTiledPattern,
|
||||
transformedPattern,
|
||||
remap);
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::Mesh(
|
||||
*pTiledPattern, transformedPattern, remap);
|
||||
for (size_t ei = 0; ei < pattern.EN(); ei++) {
|
||||
perPatternIndexToTiledPatternEdgeIndex[facePatternIndex].push_back(remap.edge[ei]);
|
||||
perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back(
|
||||
remap.edge[ei]);
|
||||
}
|
||||
// pTiledPattern->registerForDrawing();
|
||||
// pTiledPattern->markVertices({remap.vert[pattern.interfaceNodeIndex]});
|
||||
// polyscope::show();
|
||||
// pTiledPattern->unregister();
|
||||
const size_t ei = tileInto.getIndex(ep);
|
||||
tileIntoEdgeToInterfaceVi[ei].push_back(remap.vert[pattern.interfaceNodeIndex]);
|
||||
tileIntoEdgeToInterfaceVi[ei].push_back(
|
||||
remap.vert[pattern.interfaceNodeIndex]);
|
||||
// Add edges for connecting the desired vertices
|
||||
if (!connectToNeighborsVi.empty()) {
|
||||
if (vi + 1 == f.VN()) {
|
||||
|
@ -935,9 +998,9 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
auto eIt = vcg::tri::Allocator<PatternGeometry>::AddEdge(
|
||||
*pTiledPattern,
|
||||
firstInFanConnectToNeighbor_vi[connectToNeighborIndex],
|
||||
pTiledPattern->VN() - pattern.VN()
|
||||
+ connectToNeighborsVi[connectToNeighborIndex]);
|
||||
perPatternIndexToTiledPatternEdgeIndex[facePatternIndex].push_back(
|
||||
pTiledPattern->VN() - pattern.VN() +
|
||||
connectToNeighborsVi[connectToNeighborIndex]);
|
||||
perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back(
|
||||
pTiledPattern->getIndex(*eIt));
|
||||
}
|
||||
}
|
||||
|
@ -947,26 +1010,23 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
connectToNeighborIndex++) {
|
||||
auto eIt = vcg::tri::Allocator<PatternGeometry>::AddEdge(
|
||||
*pTiledPattern,
|
||||
pTiledPattern->VN() - 2 * pattern.VN()
|
||||
+ connectToNeighborsVi[connectToNeighborIndex],
|
||||
pTiledPattern->VN() - pattern.VN()
|
||||
+ connectToNeighborsVi[connectToNeighborIndex]);
|
||||
perPatternIndexToTiledPatternEdgeIndex[facePatternIndex].push_back(
|
||||
pTiledPattern->VN() - 2 * pattern.VN() +
|
||||
connectToNeighborsVi[connectToNeighborIndex],
|
||||
pTiledPattern->VN() - pattern.VN() +
|
||||
connectToNeighborsVi[connectToNeighborIndex]);
|
||||
perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back(
|
||||
pTiledPattern->getIndex(*eIt));
|
||||
}
|
||||
}
|
||||
}
|
||||
// tiledPattern.updateEigenEdgeAndVertices();
|
||||
// tiledPattern.registerForDrawing();
|
||||
|
||||
// polyscope::show();
|
||||
}
|
||||
}
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<VertexPointer> pu_vertices;
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::PointerUpdater<EdgePointer> pu_edges;
|
||||
pTiledPattern->removeDuplicateVertices(pu_vertices, pu_edges);
|
||||
// Update perPattern
|
||||
// for (std::vector<size_t> &tiledPatternEdges : perPatternIndexToTiledPatternEdgeIndex) {
|
||||
// for (std::vector<size_t> &tiledPatternEdges :
|
||||
// perPatternIndexToTiledPatternEdgeIndex) {
|
||||
// for (size_t &ei : tiledPatternEdges) {
|
||||
// ei = pu_edges.remap[ei];
|
||||
// }
|
||||
|
@ -978,14 +1038,15 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
|
||||
// tiledPatternEdges.erase(end, tiledPatternEdges.end());
|
||||
// }
|
||||
const size_t sumOfEdgeIndices = std::accumulate(perPatternIndexToTiledPatternEdgeIndex.begin(),
|
||||
perPatternIndexToTiledPatternEdgeIndex.end(),
|
||||
0,
|
||||
[](const size_t &sum,
|
||||
const std::vector<size_t> &v) {
|
||||
|
||||
const size_t sumOfEdgeIndices =
|
||||
std::accumulate(perPatternIndexToTiledPatternEdgeIndex.begin(),
|
||||
perPatternIndexToTiledPatternEdgeIndex.end(), 0,
|
||||
[](const size_t& sum, const std::vector<size_t>& v) {
|
||||
return sum + v.size();
|
||||
});
|
||||
|
||||
const int en = pTiledPattern->EN();
|
||||
assert(pTiledPattern->EN() == sumOfEdgeIndices);
|
||||
|
||||
tileIntoEdgesToTiledVi.clear();
|
||||
|
@ -997,22 +1058,22 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
|
|||
}
|
||||
assert(interfaceVis.size() == 1 || interfaceVis.size() == 2);
|
||||
assert(
|
||||
interfaceVis.size() == 1
|
||||
|| (interfaceVis.size() == 2
|
||||
&& (pu_vertices.remap[interfaceVis[0]] == std::numeric_limits<size_t>::max()
|
||||
|| pu_vertices.remap[interfaceVis[1]] == std::numeric_limits<size_t>::max())));
|
||||
interfaceVis.size() == 1 ||
|
||||
(interfaceVis.size() == 2 && (pu_vertices.remap[interfaceVis[0]] ==
|
||||
std::numeric_limits<size_t>::max() ||
|
||||
pu_vertices.remap[interfaceVis[1]] ==
|
||||
std::numeric_limits<size_t>::max())));
|
||||
tileIntoEdgesToTiledVi[ei] = pu_vertices.remap[interfaceVis[0]];
|
||||
}
|
||||
|
||||
pTiledPattern->deleteDanglingVertices();
|
||||
vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(*pTiledPattern);
|
||||
pTiledPattern->updateEigenEdgeAndVertices();
|
||||
pTiledPattern->save();
|
||||
// pTiledPattern->save();
|
||||
return pTiledPattern;
|
||||
}
|
||||
|
||||
bool PatternGeometry::createHoneycombAtom()
|
||||
{
|
||||
bool PatternGeometry::createHoneycombAtom() {
|
||||
VCGEdgeMesh honeycombQuarter;
|
||||
const VCGEdgeMesh::CoordType n(0, 0, 1);
|
||||
const double H = 0.2;
|
||||
|
@ -1020,38 +1081,38 @@ bool PatternGeometry::createHoneycombAtom()
|
|||
const double width = 0.2;
|
||||
const double theta = 70;
|
||||
const double dy = tan(vcg::math::ToRad(90 - theta)) * width / 2;
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(honeycombQuarter,
|
||||
VCGEdgeMesh::CoordType(0, height / 2, 0),
|
||||
n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(honeycombQuarter,
|
||||
VCGEdgeMesh::CoordType(0, H / 2 - dy, 0),
|
||||
n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(honeycombQuarter,
|
||||
VCGEdgeMesh::CoordType(width / 2, H / 2, 0),
|
||||
n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(honeycombQuarter,
|
||||
VCGEdgeMesh::CoordType(width / 2, 0, 0),
|
||||
n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(
|
||||
honeycombQuarter, VCGEdgeMesh::CoordType(0, height / 2, 0), n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(
|
||||
honeycombQuarter, VCGEdgeMesh::CoordType(0, H / 2 - dy, 0), n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(
|
||||
honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, H / 2, 0), n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(
|
||||
honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, 0, 0), n);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(honeycombQuarter, 0, 1);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(honeycombQuarter, 1, 2);
|
||||
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(honeycombQuarter, 2, 3);
|
||||
|
||||
VCGEdgeMesh honeycombAtom;
|
||||
// Top right
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::MeshCopy(honeycombAtom, honeycombQuarter);
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::MeshCopy(honeycombAtom,
|
||||
honeycombQuarter);
|
||||
// Bottom right
|
||||
vcg::Matrix44d rotM;
|
||||
rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0));
|
||||
vcg::tri::UpdatePosition<VCGEdgeMesh>::Matrix(honeycombQuarter, rotM);
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::Mesh(honeycombAtom, honeycombQuarter);
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::Mesh(honeycombAtom,
|
||||
honeycombQuarter);
|
||||
// Bottom left
|
||||
rotM.SetRotateDeg(180, vcg::Point3d(0, 1, 0));
|
||||
vcg::tri::UpdatePosition<VCGEdgeMesh>::Matrix(honeycombQuarter, rotM);
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::Mesh(honeycombAtom, honeycombQuarter);
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::Mesh(honeycombAtom,
|
||||
honeycombQuarter);
|
||||
// Top left
|
||||
rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0));
|
||||
vcg::tri::UpdatePosition<VCGEdgeMesh>::Matrix(honeycombQuarter, rotM);
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::Mesh(honeycombAtom, honeycombQuarter);
|
||||
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::Mesh(honeycombAtom,
|
||||
honeycombQuarter);
|
||||
|
||||
for (VertexType& v : honeycombAtom.vert) {
|
||||
v.P()[2] = 0;
|
||||
|
@ -1060,69 +1121,51 @@ bool PatternGeometry::createHoneycombAtom()
|
|||
return true;
|
||||
}
|
||||
|
||||
void PatternGeometry::copy(PatternGeometry ©From)
|
||||
{
|
||||
void PatternGeometry::copy(PatternGeometry& copyFrom) {
|
||||
VCGEdgeMesh::copy(copyFrom);
|
||||
baseTriangleHeight = copyFrom.getBaseTriangleHeight();
|
||||
baseTriangle = copyFrom.getBaseTriangle();
|
||||
interfaceNodeIndex = copyFrom.interfaceNodeIndex;
|
||||
}
|
||||
|
||||
void PatternGeometry::scale(const double &desiredBaseTriangleCentralEdgeSize,
|
||||
const int &interfaceNodeIndex)
|
||||
{
|
||||
const double baseTriangleCentralEdgeSize = computeBaseTriangleHeight();
|
||||
const double scaleRatio = desiredBaseTriangleCentralEdgeSize / baseTriangleCentralEdgeSize;
|
||||
void PatternGeometry::scale(const double& desiredBaseTriangleCentralEdgeSize) {
|
||||
const double baseTriangleCentralEdgeSize = getBaseTriangleHeight();
|
||||
const double scaleRatio =
|
||||
desiredBaseTriangleCentralEdgeSize / baseTriangleCentralEdgeSize;
|
||||
vcg::tri::UpdatePosition<VCGEdgeMesh>::Scale(*this, scaleRatio);
|
||||
baseTriangle = computeBaseTriangle();
|
||||
baseTriangleHeight = computeBaseTriangleHeight();
|
||||
const double debug_baseTriHeight = vcg::Distance(
|
||||
baseTriangle.cP(0), (baseTriangle.cP(1) + baseTriangle.cP(2)) / 2);
|
||||
assert(std::abs(desiredBaseTriangleCentralEdgeSize - baseTriangleHeight) <
|
||||
1e-10);
|
||||
int i = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
void PatternGeometry::createFan(const std::vector<int> &connectToNeighborsVi, const size_t &fanSize)
|
||||
{
|
||||
void PatternGeometry::createFan(const size_t& fanSize) {
|
||||
PatternGeometry rotatedPattern;
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::MeshCopy(rotatedPattern, *this);
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::MeshCopy(rotatedPattern,
|
||||
*this);
|
||||
for (int rotationCounter = 1; rotationCounter < fanSize; rotationCounter++) {
|
||||
vcg::Matrix44d R;
|
||||
auto rotationAxis = vcg::Point3d(0, 0, 1);
|
||||
R.SetRotateDeg(360.0 / fanSize, rotationAxis);
|
||||
vcg::tri::UpdatePosition<PatternGeometry>::Matrix(rotatedPattern, R);
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::Mesh(*this, rotatedPattern);
|
||||
vcg::tri::Append<PatternGeometry, PatternGeometry>::Mesh(*this,
|
||||
rotatedPattern);
|
||||
// Add edges for connecting the desired vertices
|
||||
if (!connectToNeighborsVi.empty()) {
|
||||
if (rotationCounter == fanSize - 1) {
|
||||
for (int connectToNeighborIndex = 0;
|
||||
connectToNeighborIndex < connectToNeighborsVi.size();
|
||||
connectToNeighborIndex++) {
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(
|
||||
*this,
|
||||
connectToNeighborsVi[connectToNeighborIndex],
|
||||
this->VN() - rotatedPattern.VN()
|
||||
+ connectToNeighborsVi[connectToNeighborIndex]);
|
||||
}
|
||||
}
|
||||
for (int connectToNeighborIndex = 0;
|
||||
connectToNeighborIndex < connectToNeighborsVi.size();
|
||||
connectToNeighborIndex++) {
|
||||
vcg::tri::Allocator<PatternGeometry>::AddEdge(
|
||||
*this,
|
||||
this->VN() - 2 * rotatedPattern.VN()
|
||||
+ connectToNeighborsVi[connectToNeighborIndex],
|
||||
this->VN() - rotatedPattern.VN() + connectToNeighborsVi[connectToNeighborIndex]);
|
||||
}
|
||||
}
|
||||
removeDuplicateVertices();
|
||||
updateEigenEdgeAndVertices();
|
||||
}
|
||||
}
|
||||
|
||||
double PatternGeometry::getBaseTriangleHeight() const
|
||||
{
|
||||
double PatternGeometry::getBaseTriangleHeight() const {
|
||||
return baseTriangleHeight;
|
||||
}
|
||||
|
||||
bool PatternGeometry::isInterfaceConnected(const std::unordered_set<VertexIndex> &interfaceNodes)
|
||||
{
|
||||
bool PatternGeometry::isInterfaceConnected(
|
||||
const std::unordered_set<VertexIndex>& interfaceNodes) {
|
||||
std::unordered_set<VertexIndex> interfaceNodesConnected;
|
||||
|
||||
for (int ei = 0; ei < EN(); ei++) {
|
||||
|
@ -1130,7 +1173,8 @@ bool PatternGeometry::isInterfaceConnected(const std::unordered_set<VertexIndex>
|
|||
const int evi1 = getIndex(edge[ei].cV(1));
|
||||
if (interfaceNodes.contains(evi0) && !interfaceNodes.contains(evi1)) {
|
||||
interfaceNodesConnected.insert(evi0);
|
||||
} else if (!interfaceNodes.contains(evi0) && interfaceNodes.contains(evi1)) {
|
||||
} else if (!interfaceNodes.contains(evi0) &&
|
||||
interfaceNodes.contains(evi1)) {
|
||||
interfaceNodesConnected.insert(evi1);
|
||||
}
|
||||
}
|
||||
|
@ -1142,10 +1186,10 @@ bool PatternGeometry::isInterfaceConnected(const std::unordered_set<VertexIndex>
|
|||
}
|
||||
|
||||
std::unordered_set<VertexIndex> PatternGeometry::getInterfaceNodes(
|
||||
const std::vector<size_t> &numberOfNodesPerSlot)
|
||||
{
|
||||
const std::vector<size_t>& numberOfNodesPerSlot) {
|
||||
if (nodeToSlotMap.empty()) {
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap);
|
||||
FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot,
|
||||
nodeToSlotMap);
|
||||
}
|
||||
std::unordered_set<VertexIndex> interfaceNodes;
|
||||
for (std::pair<VertexIndex, size_t> viSlotPair : nodeToSlotMap) {
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
#ifndef FLATPATTERNGEOMETRY_HPP
|
||||
#define FLATPATTERNGEOMETRY_HPP
|
||||
#include "edgemesh.hpp"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "vcgtrimesh.hpp"
|
||||
#include "edgemesh.hpp"
|
||||
#include "polymesh.hpp"
|
||||
#include "vcgtrimesh.hpp"
|
||||
|
||||
class PatternGeometry;
|
||||
using ConstPatternGeometry = PatternGeometry;
|
||||
|
||||
class PatternGeometry : public VCGEdgeMesh
|
||||
{
|
||||
class PatternGeometry : public VCGEdgeMesh {
|
||||
private:
|
||||
size_t
|
||||
computeTiledValence(const size_t &nodeIndex,
|
||||
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;
|
||||
|
@ -31,15 +29,18 @@ private:
|
|||
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,
|
||||
std::vector<VectorType> getEdgeVectorsWithVertexAsOrigin(
|
||||
std::vector<EdgePointer>& edgePointers,
|
||||
const int& vi);
|
||||
|
||||
public:
|
||||
inline static VectorType DefaultNormal{0.0, 0.0, 1.0};
|
||||
PatternGeometry();
|
||||
/*The following function should be a copy constructor with
|
||||
* a const argument but this is impossible due to the
|
||||
|
@ -49,22 +50,24 @@ private:
|
|||
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<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);
|
||||
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;
|
||||
std::vector<vcg::Point3d> computeVertices() 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);
|
||||
|
@ -74,8 +77,8 @@ private:
|
|||
|
||||
bool hasIntersectingEdges(
|
||||
const std::string& patternBinaryRepresentation,
|
||||
const std::unordered_map<size_t, std::unordered_set<size_t>>
|
||||
&intersectingEdges);
|
||||
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,
|
||||
|
@ -83,7 +86,8 @@ private:
|
|||
|
||||
PatternGeometry(const std::vector<size_t>& numberOfNodesPerSlot,
|
||||
const std::vector<vcg::Point2i>& edges);
|
||||
PatternGeometry(const std::string &filename, bool addNormalsIfAbsent = true);
|
||||
PatternGeometry(const std::filesystem::path& patternFilePath,
|
||||
bool addNormalsIfAbsent = true);
|
||||
|
||||
bool createHoneycombAtom();
|
||||
void copy(PatternGeometry& copyFrom);
|
||||
|
@ -93,25 +97,34 @@ private:
|
|||
const int& interfaceNodeIndex,
|
||||
const bool& shouldDeleteDanglingEdges);
|
||||
|
||||
void scale(const double &desiredBaseTriangleCentralEdgeSize, const int &interfaceNodeIndex);
|
||||
void scale(const double& desiredBaseTriangleCentralEdgeSize);
|
||||
|
||||
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);
|
||||
void createFan(const std::vector<int> &connectToNeighborsVi = std::vector<int>(),
|
||||
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);
|
||||
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);
|
||||
vcg::Triangle3<double> getBaseTriangle() const;
|
||||
static std::shared_ptr<PatternGeometry> tilePattern(PatternGeometry &pattern,
|
||||
static std::shared_ptr<PatternGeometry> tilePattern(
|
||||
PatternGeometry& pattern,
|
||||
const std::vector<int>& connectToNeighborsVi,
|
||||
const VCGPolyMesh& tileInto,
|
||||
std::vector<int>& tileIntoEdgesToTiledVi);
|
||||
|
@ -122,11 +135,14 @@ private:
|
|||
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::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
|
||||
|
|
472
utilities.hpp
472
utilities.hpp
|
@ -1,472 +0,0 @@
|
|||
#ifndef UTILITIES_H
|
||||
#define UTILITIES_H
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <regex>
|
||||
|
||||
#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,6 +6,9 @@
|
|||
#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));
|
||||
|
@ -36,6 +39,32 @@ 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);
|
||||
|
@ -92,8 +121,7 @@ bool VCGTriMesh::save(const std::string plyFilename)
|
|||
|
||||
#ifdef POLYSCOPE_DEFINED
|
||||
|
||||
polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing(
|
||||
const std::optional<std::array<double, 3>> &desiredColor, const bool &shouldEnable) const
|
||||
polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing(const std::optional<std::array<float, 3> > &desiredColor, const bool &shouldEnable) const
|
||||
{
|
||||
auto vertices = getVertices();
|
||||
auto faces = getFaces();
|
||||
|
@ -117,7 +145,7 @@ polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing(
|
|||
const glm::vec3 desiredColor_glm(desiredColor.value()[0],
|
||||
desiredColor.value()[1],
|
||||
desiredColor.value()[2]);
|
||||
polyscopeHandle_mesh->setSurfaceColor(glm::normalize(desiredColor_glm));
|
||||
polyscopeHandle_mesh->setSurfaceColor(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,34 +22,37 @@ 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::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 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 Mesh {
|
||||
public:
|
||||
VCGTriMesh();
|
||||
VCGTriMesh(const std::string& filename);
|
||||
bool load(const std::filesystem::path& meshFilePath) override;
|
||||
bool load(std::istringstream& offInputStream);
|
||||
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<double, 3>> &desiredColor = std::nullopt,
|
||||
const std::optional<std::array<float, 3>>& desiredColor = std::nullopt,
|
||||
const bool& shouldEnable = true) const;
|
||||
#endif
|
||||
Eigen::MatrixX2i getEdges() const;
|
||||
|
|
Loading…
Reference in New Issue