Compare commits

...

72 Commits

Author SHA1 Message Date
iasonmanolas 3c664856ef Refactoring 2022-10-20 13:35:31 +03:00
iasonmanolas 76433eaa9d Refactoring 2022-10-20 13:34:53 +03:00
iasonmanolas db8aa4124e Removed some scenarios. Scaling the forces of the scenarios 2022-10-20 13:34:05 +03:00
iasonmanolas 6e08bc039b Newer version 2022-10-20 13:33:01 +03:00
iasonmanolas 158db04660 Refactoring 2022-10-20 13:32:42 +03:00
iasonmanolas 266aca08c2 Backup commit 2022-09-14 13:04:05 +02:00
iasonmanolas 01dff95f9d Refactoring 2022-08-08 12:03:04 +03:00
iasonmanolas dd21445f52 Added linear and non linear chronos euler simulation model classes in order to be able to out-of-the-box use them with a factory class 2022-08-08 12:02:41 +03:00
iasonmanolas 68d5655214 Added linear and non linear chronos euler simulation model classes in order to be able to out-of-the-box use them with a factory class 2022-08-08 12:02:14 +03:00
iasonmanolas 9fd536ccf3 Added linear and non linear chronos euler simulation model classes in order to be able to out-of-the-box use them with a factory class 2022-08-08 11:44:55 +03:00
iasonmanolas 7780e4ab38 Moved files to DRMSimulationModel project 2022-07-28 13:23:54 +03:00
iasonmanolas 90551e5485 Using quadratic reset. Unit tests 2120 ,3333,9268 iterations 2022-07-26 20:04:07 +03:00
iasonmanolas 76fb1b8609 Refactoring 2022-07-22 12:19:47 +03:00
iasonmanolas 164f156aa7 Added virtual destructor since I use destruction on pointers to derived class 2022-07-22 12:17:31 +03:00
iasonmanolas 382ef273a4 Edited computeDIstance function for comparing simulation results in order to work with generic containers 2022-07-22 12:16:56 +03:00
iasonmanolas 6762c266c0 Added simulation model factory class. refactoring 2022-07-22 12:15:52 +03:00
iasonmanolas 3092809d02 Added chronos IGA simulation model 2022-07-22 12:13:45 +03:00
iasonmanolas d8a6fadab7 Added simulation model used in the optimization results struct 2022-07-20 10:49:09 +03:00
iasonmanolas 7a0124155c Uses chronos simulation model. Refactoring 2022-07-19 14:59:05 +03:00
iasonmanolas ef18646cfd Refactoring 2022-07-19 14:54:39 +03:00
iasonmanolas 96e63d15a3 Refactoring. Uses new dimension function 2022-07-19 14:49:32 +03:00
iasonmanolas 8f80c654b2 Added base class. Added getDrawingRadius() function 2022-07-19 14:48:30 +03:00
iasonmanolas cb1d6b811d Refactoring. Made library static 2022-07-19 14:47:31 +03:00
iasonmanolas bed30a2bc4 Refactoring 2022-07-12 13:13:01 +03:00
iasonmanolas 395bf92486 Refactoring 2022-07-12 13:12:33 +03:00
iasonmanolas ba52c4215e Refactoring 2022-07-12 13:11:14 +03:00
iasonmanolas 0d07f1c831 Added beamWidth and beamHeight static variables 2022-07-12 13:10:38 +03:00
iasonmanolas b4fb31748c Added beamWidth and beamHeight static variables 2022-07-12 13:10:14 +03:00
iasonmanolas a0ed388c56 Added choice of simulation model for the pattern tessellation simulation. Refactoring 2022-07-12 13:09:25 +03:00
iasonmanolas 2c462d9ebf Refactoring 2022-07-12 13:08:21 +03:00
iasonmanolas 50045330ae added appendToLabel 2022-07-12 13:07:51 +03:00
iasonmanolas db35df38fc Refactoring.Added function for exporting to svg 2022-07-12 13:07:21 +03:00
iasonmanolas fd5e9755ab added simulation model label 2022-07-12 13:06:37 +03:00
iasonmanolas b4928c720b Added functions for parsing SimulationJob 2022-07-12 13:01:23 +03:00
iasonmanolas adaf49627f Refactoring 2022-07-12 13:00:45 +03:00
iasonmanolas e70b4e9863 Changed default normal. Identical cantilever results with panettaD 2022-07-12 13:00:11 +03:00
iasonmanolas 9d9f7dbacf Chronos is being used for computing the ground truth of the pattern during the reduced model optimization 2022-07-08 15:53:17 +03:00
iasonmanolas 8a335411d9 Leimer implementation of DER. Implemented interface with my SimulationJob structure 2022-06-30 15:26:41 +03:00
iasonmanolas c3802cfc87 Refactoring 2022-05-12 09:24:32 +03:00
iasonmanolas d02587c1b8 refa 2022-05-11 14:26:05 +03:00
iasonmanolas 27548bd7b0 Commented unused code 2022-05-11 13:25:58 +03:00
iasonmanolas 897bb4400a Changed drawing radius 2022-05-11 13:25:33 +03:00
iasonmanolas 54da8ac343 Added chronos interface class 2022-05-11 13:25:17 +03:00
iasonmanolas 3e5dc29bc1 Removed file 2022-05-06 16:40:31 +03:00
iasonmanolas b2bd12d8df Hardcoded the 22 hexagon test-surface 2022-05-06 16:40:05 +03:00
iasonmanolas 90dc2ac081 Refactoring. Replaced PatternGeometry with ReducedModel everywhere 2022-05-06 16:38:50 +03:00
iasonmanolas 7f11ea8a47 refactoring. Added functionality to export internal forces 2022-05-06 16:36:47 +03:00
iasonmanolas f531b16b19 Added function for loading tri mes using istringstream 2022-05-06 16:28:28 +03:00
iasonmanolas 398df24056 Moved implementations to cpp file 2022-05-06 16:27:37 +03:00
iasonmanolas 0cb175e72e Added functions for changing the geometry and material props of the reduced model 2022-05-06 16:27:00 +03:00
iasonmanolas a7fdf431dd Refactoring 2022-05-06 16:26:05 +03:00
iasonmanolas e9707e2cfb Refactoring 2022-05-06 16:16:43 +03:00
iasonmanolas 436ece0d88 Refactoring 2022-05-06 16:12:42 +03:00
iasonmanolas 3d0de46922 Added the S scenario. Refactoring 2022-02-18 17:50:16 +02:00
iasonmanolas 96807c3b85 Moved global variable to struct when ensmallen is used. And left the global variable when dlib is used for optimization. Added the S scenario. Removed static keyword from several functions 2022-02-18 17:49:17 +02:00
iasonmanolas 5c4f8c0bd5 Added Settings struct. Expanded printing of evaluation results.Refactoring 2022-02-18 17:46:28 +02:00
iasonmanolas 45eed0e3da Moved string with precision function to Utilities namespace 2022-02-18 17:45:14 +02:00
iasonmanolas bef2ae8860 Renamed getEdges and getVertices to computeEdges and computeVertices 2022-02-18 17:44:33 +02:00
iasonmanolas ec7160e637 Renamed getEdges and getVertices to computeEdges and computeVertices 2022-02-18 17:43:07 +02:00
iasonmanolas 6c16d8d48e Renamed getEdges and getVertices to computeEdges and computeVertices 2022-02-18 17:42:47 +02:00
iasonmanolas 5f863af7ce Refactoring 2022-02-18 17:41:37 +02:00
iasonmanolas e1f66515d5 Renamed getEdges and getVertices to computeEdges and computeVertices 2022-02-18 17:40:56 +02:00
iasonmanolas 9e121beade Made parse function of csvFile struct return a vector<vector<string>> instead of being a template function 2022-02-18 17:39:02 +02:00
iasonmanolas 33facf05ab Fixed bug 2022-02-01 13:08:07 +02:00
iasonmanolas e54dc0a27c Changed hardcoded directory of tessellated results 2022-02-01 13:06:53 +02:00
iasonmanolas 7f543ef21a Added computation of internal forces in the converged state 2022-02-01 13:06:16 +02:00
iasonmanolas 366727ced6 Refactoring 2022-01-28 20:06:56 +02:00
iasonmanolas 068626f299 Refactoring 2022-01-28 20:01:44 +02:00
iasonmanolas c513abc45b Added dlib to dependencies since I move the reducedmodeloptimizer to MySources. Refacoting 2022-01-28 19:59:42 +02:00
iasonmanolas 8e33ba35aa Moved the reduced model optimizer class to MySources 2022-01-27 14:45:54 +02:00
iasonmanolas 38c2535a34 Added reduced model class that handles the reduced model in terms of construction 2022-01-27 14:45:16 +02:00
iasonmanolas 643e8b35be Added reduced model class that handles the reduced model in terms of construction 2022-01-27 14:44:30 +02:00
59 changed files with 25631 additions and 20092 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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;
}

4845
der_leimer.cpp Normal file

File diff suppressed because it is too large Load Diff

193
der_leimer.hpp Normal file
View File

@ -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 &params,
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 &params,
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 &params,
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

View File

@ -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

View File

@ -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 &degreesOfArm,
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

View File

@ -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 &degreesOfArm, 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

175
nlohmann/json_fwd.hpp Normal file
View File

@ -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_

View File

@ -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 &copyFrom)
{
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 &copyFrom) { 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

94
reducedmodel.cpp Normal file
View File

@ -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();
}
}

20
reducedmodel.hpp Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

2695
reducedmodeloptimizer.cpp Normal file

File diff suppressed because it is too large Load Diff

417
reducedmodeloptimizer.hpp Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 &copyFrom)
{
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) {

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;