5 changed files with 393 additions and 190 deletions
@ -0,0 +1,233 @@ |
|||
//
|
|||
// Created by cflin on 4/14/23.
|
|||
//
|
|||
#include <igl/file_dialog_save.h> |
|||
#include "StaticSimGUI.h" |
|||
#include "Util.h" |
|||
namespace ssim{ |
|||
|
|||
void StaticSimGUI::menu_draw_viewer_menu() { |
|||
// Draw parent menu content
|
|||
// menu_.draw_viewer_menu();
|
|||
|
|||
auto io_menu = [&]() { |
|||
if (ImGui::Button("加载文件##IO", ImVec2(-1, 0))) { |
|||
#ifndef DEBUG_SSIM |
|||
std::string f_json = igl::file_dialog_open(); |
|||
if (f_json != "" ) { |
|||
reload_json(f_json); |
|||
gui_ctrl_.is_initialized = true; |
|||
gui_ctrl_.is_loaded_json = true; |
|||
} |
|||
#else |
|||
load(CMAKE_SOURCE_DIR "/sim-test/rigid-test/rocker-arm/config.json"); |
|||
#endif |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
}; |
|||
auto model_menu = [&]() { |
|||
|
|||
if (ImGui::Checkbox("网格可视化", &gui_ctrl_.is_visible_mesh)) { |
|||
gui_ctrl_.is_modified = true; |
|||
} |
|||
|
|||
|
|||
// --------------------------------------------------------------------
|
|||
if (ImGui::CollapsingHeader("边界条件", ImGuiTreeNodeFlags_DefaultOpen)) { |
|||
|
|||
if (ImGui::Checkbox("边界可视化", &gui_ctrl_.is_visible_BC)) { |
|||
gui_ctrl_.is_modified = true; |
|||
} |
|||
|
|||
if (ImGui::CollapsingHeader( |
|||
"Dirichlet边界", ImGuiTreeNodeFlags_Leaf)) { |
|||
// --------------------------------------------------------------------
|
|||
|
|||
for (int i = 0; i < sp_StaticSim_->DirichletBCs.size(); ++i) { |
|||
// each boundary
|
|||
// ImGui::Checkbox("受力", &m_state.m_solve_collisions);
|
|||
auto &i_DBC = sp_StaticSim_->DirichletBCs[i]; |
|||
std::vector<float> v_min_point = {(float) i_DBC.relMinBBox.x(), |
|||
(float) i_DBC.relMinBBox.y(), |
|||
(float) i_DBC.relMinBBox.z()}; |
|||
std::vector<float> v_max_point = {(float) i_DBC.relMaxBBox.x(), |
|||
(float) i_DBC.relMaxBBox.y(), |
|||
(float) i_DBC.relMaxBBox.z()}; |
|||
if (ImGui::InputFloat3(("Dirichlet最小值 " + std::to_string(i + 1)).c_str(), |
|||
v_min_point.data()) || |
|||
ImGui::InputFloat3(("Dirichlet最大值 " + std::to_string(i + 1)).c_str(), |
|||
v_max_point.data())) { |
|||
gui_ctrl_.is_modified = true; |
|||
i_DBC.relMinBBox = {v_min_point[0], v_min_point[1], v_min_point[2]}; |
|||
i_DBC.relMaxBBox = {v_max_point[0], v_max_point[1], v_max_point[2]}; |
|||
} |
|||
} |
|||
if (gui_ctrl_.is_modified) { |
|||
sp_StaticSim_->updateBC(); |
|||
} |
|||
} |
|||
|
|||
if (ImGui::CollapsingHeader( |
|||
"Neumann边界", ImGuiTreeNodeFlags_Leaf)) { |
|||
// --------------------------------------------------------------------
|
|||
|
|||
for (int i = 0; i < sp_StaticSim_->NeumannBCs.size(); ++i) { |
|||
auto &i_NBC = sp_StaticSim_->NeumannBCs[i]; |
|||
std::vector<float> v_min_point = {(float) i_NBC.relMinBBox.x(), |
|||
(float) i_NBC.relMinBBox.y(), |
|||
(float) i_NBC.relMinBBox.z()}; |
|||
std::vector<float> v_max_point = {(float) i_NBC.relMaxBBox.x(), |
|||
(float) i_NBC.relMaxBBox.y(), |
|||
(float) i_NBC.relMaxBBox.z()}; |
|||
std::vector<float> v_force = {(float) i_NBC.force.x(), (float) i_NBC.force.y(), |
|||
(float) i_NBC.force.z()}; |
|||
if ( |
|||
ImGui::InputFloat3(("Neumann最小值 " + std::to_string(i + 1)).c_str(), |
|||
v_min_point.data()) || |
|||
ImGui::InputFloat3(("Neumann最大值 " + std::to_string(i + 1)).c_str(), |
|||
v_max_point.data()) || |
|||
ImGui::InputFloat3(("Neumann力 " + std::to_string(i + 1)).c_str(), |
|||
v_force.data())) { |
|||
gui_ctrl_.is_modified = true; |
|||
i_NBC.relMinBBox = {v_min_point[0], v_min_point[1], v_min_point[2]}; |
|||
i_NBC.relMaxBBox = {v_max_point[0], v_max_point[1], v_max_point[2]}; |
|||
i_NBC.force = {v_force[0], v_force[1], v_force[2]}; |
|||
|
|||
} |
|||
} |
|||
if (gui_ctrl_.is_modified) { |
|||
sp_StaticSim_->updateBC(); |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// --------------------------------------------------------------------
|
|||
if (ImGui::CollapsingHeader("材料设置", ImGuiTreeNodeFlags_DefaultOpen)) { |
|||
|
|||
ImGui::InputFloat("杨氏模量", &sp_StaticSim_->get_material_property().Youngs_Modulus, 1.0f, 1e10f, |
|||
"%.3f"); |
|||
ImGui::InputFloat("泊松比", &sp_StaticSim_->get_material_property().Poisson_ratio, 0.01f, 1.0f, |
|||
"%.3f"); |
|||
ImGui::InputFloat("密度", &sp_StaticSim_->get_material_property().density, 1.0f, 1000.0f, "%.3f"); |
|||
} |
|||
|
|||
if (ImGui::Button(("原始模型"), ImVec2(-1, 0))) { |
|||
gui_ctrl_.is_single_color = true; |
|||
gui_ctrl_.is_modified = true; |
|||
} |
|||
|
|||
if (ImGui::Button("开始计算", ImVec2(-1, 0))) { |
|||
sp_StaticSim_->simulation(); |
|||
gui_ctrl_.is_modified = true; |
|||
gui_ctrl_.is_solved = true; |
|||
gui_ctrl_.is_single_color = false; |
|||
gui_ctrl_.is_visible_BC = false; |
|||
|
|||
} |
|||
}; |
|||
auto result_menu = [&]() { |
|||
ImGui::TextWrapped("柔顺度 (compliance): %.3e", |
|||
sp_StaticSim_->EvaluateTarget(ssim::SimTargetOption::COMPLIANCE)(0, 0)); |
|||
static const ImVec2 button_size(200,40); |
|||
static bool arr_extract[SimTargetOption::Target::ENUM_SIZE]={false}; |
|||
int idx=0; |
|||
if (ImGui::Button("位移范数",button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::U_NORM); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出位移范数",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("位移-X", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::UX); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出位移-X",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("位移-Y", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::UY); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出位移-Y",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("位移-Z", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::UZ); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出位移-Z",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("应力范数", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::S_NORM); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出应力范数",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("冯氏应力", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::S_VON_Mises); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出冯氏应力",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("应力-X", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::SX); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出应力-X",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("应力-Y", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::SY); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出应力-Y",arr_extract+idx); |
|||
++idx; |
|||
|
|||
if (ImGui::Button("应力-Z", button_size)) { |
|||
gui_ctrl_.set_target(ssim::SimTargetOption::Target::SZ); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出应力-Z",arr_extract+idx); |
|||
++idx; |
|||
|
|||
static bool is_extract_coord= false; |
|||
if(ImGui::Button("导出结果文件",button_size)){ |
|||
std::string extract_dir=ssim::directory_dialog_save(); |
|||
spdlog::info("extract to: {}",extract_dir); |
|||
std::vector<bool> v_is_extract(arr_extract,arr_extract+SimTargetOption::Target::ENUM_SIZE); |
|||
sp_StaticSim_->ExtractTarget(extract_dir,v_is_extract,is_extract_coord); |
|||
} |
|||
ImGui::SameLine(); |
|||
ImGui::Checkbox("导出坐标",&is_extract_coord); |
|||
|
|||
}; |
|||
|
|||
|
|||
if (ImGui::CollapsingHeader("载入模型", ImGuiTreeNodeFlags_DefaultOpen)) { |
|||
io_menu(); |
|||
} |
|||
if (!gui_ctrl_.is_initialized && gui_ctrl_.is_loaded_json) { |
|||
if (ImGui::CollapsingHeader("模型设置", ImGuiTreeNodeFlags_DefaultOpen)) { |
|||
model_menu(); |
|||
} |
|||
|
|||
if (gui_ctrl_.is_solved) { |
|||
if (ImGui::CollapsingHeader("仿真结果", ImGuiTreeNodeFlags_DefaultOpen)) { |
|||
result_menu(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,116 @@ |
|||
//
|
|||
// Created by cflin on 4/14/23.
|
|||
//
|
|||
|
|||
#ifndef EXAMPLE_UTIL_H |
|||
#define EXAMPLE_UTIL_H |
|||
#include <string> |
|||
#include <cstdio> |
|||
#include <cstring> |
|||
|
|||
#ifdef _WIN32 |
|||
#include <windows.h> |
|||
#include <Commdlg.h> |
|||
#endif |
|||
namespace ssim { |
|||
|
|||
inline std::string directory_dialog_save(){ |
|||
const int FILE_DIALOG_MAX_BUFFER = 1024; |
|||
char buffer[FILE_DIALOG_MAX_BUFFER]; |
|||
buffer[0] = '\0'; |
|||
buffer[FILE_DIALOG_MAX_BUFFER - 1] = 'x'; // Initialize last character with a char != '\0'
|
|||
|
|||
#ifdef __APPLE__ |
|||
// For apple use applescript hack
|
|||
// There is currently a bug in Applescript that strips extensions off
|
|||
// of chosen existing files in the "choose file name" dialog
|
|||
// I'm assuming that will be fixed soon
|
|||
FILE * output = popen( |
|||
"osascript -e \"" |
|||
" tell application \\\"System Events\\\"\n" |
|||
" activate\n" |
|||
" set existing_file to choose file name\n" |
|||
" end tell\n" |
|||
" set existing_file_path to (POSIX path of (existing_file))\n" |
|||
"\" 2>/dev/null | tr -d '\n' ","r"); |
|||
if (output) |
|||
{ |
|||
auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output); |
|||
if (ret == NULL || ferror(output)) |
|||
{ |
|||
// I/O error
|
|||
buffer[0] = '\0'; |
|||
} |
|||
if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0') |
|||
{ |
|||
// File name too long, buffer has been filled, so we return empty string instead
|
|||
buffer[0] = '\0'; |
|||
} |
|||
} |
|||
#elif defined _WIN32 |
|||
|
|||
// Use native windows file dialog box
|
|||
// (code contributed by Tino Weinkauf)
|
|||
|
|||
OPENFILENAME ofn; // common dialog box structure
|
|||
char szFile[260]; // buffer for file name
|
|||
|
|||
// Initialize OPENFILENAME
|
|||
ZeroMemory(&ofn, sizeof(ofn)); |
|||
ofn.lStructSize = sizeof(ofn); |
|||
ofn.hwndOwner = NULL;//hwnd;
|
|||
ofn.lpstrFile = szDir; |
|||
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
|
|||
// use the contents of szFile to initialize itself.
|
|||
ofn.lpstrFile[0] = '\0'; |
|||
ofn.nMaxFile = sizeof(szDir); |
|||
ofn.lpstrFilter = ""; |
|||
ofn.nFilterIndex = 1; |
|||
ofn.lpstrFileTitle = NULL; |
|||
ofn.nMaxFileTitle = 0; |
|||
ofn.lpstrInitialDir = NULL; |
|||
ofn.Flags = OFN_PATHMUSTEXIST; |
|||
|
|||
// Display the Open dialog box.
|
|||
int pos = 0; |
|||
if (GetSaveFileName(&ofn)==TRUE) |
|||
{ |
|||
while(ofn.lpstrFile[pos] != '\0') |
|||
{ |
|||
buffer[pos] = (char)ofn.lpstrFile[pos]; |
|||
pos++; |
|||
} |
|||
buffer[pos] = 0; |
|||
} |
|||
|
|||
#else |
|||
// For every other machine type use zenity
|
|||
FILE * output = popen("/usr/bin/zenity --directory --file-selection --save","r"); |
|||
if (output) |
|||
{ |
|||
auto ret = fgets(buffer, FILE_DIALOG_MAX_BUFFER, output); |
|||
if (ret == NULL || ferror(output)) |
|||
{ |
|||
// I/O error
|
|||
buffer[0] = '\0'; |
|||
} |
|||
if (buffer[FILE_DIALOG_MAX_BUFFER - 1] == '\0') |
|||
{ |
|||
// File name too long, buffer has been filled, so we return empty string instead
|
|||
buffer[0] = '\0'; |
|||
} |
|||
} |
|||
|
|||
// Replace last '\n' by '\0'
|
|||
if(strlen(buffer) > 0) |
|||
{ |
|||
buffer[strlen(buffer)-1] = '\0'; |
|||
} |
|||
|
|||
#endif |
|||
return std::string(buffer); |
|||
} |
|||
|
|||
} // ssim
|
|||
|
|||
#endif //EXAMPLE_UTIL_H
|
Loading…
Reference in new issue