diff --git a/CMakeLists.txt b/CMakeLists.txt index c860c20..97becf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,3 +54,4 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/sim-test/rigid-test) target_link_libraries(${PROJECT_NAME} PUBLIC StaticSim) target_compile_definitions(${PROJECT_NAME} PUBLIC CMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}") +#add_compile_definitions(DEBUG_SSIM) # for auto load json \ No newline at end of file diff --git a/src/static_sim/SimTargetOption.cpp b/src/static_sim/SimTargetOption.cpp new file mode 100644 index 0000000..5661702 --- /dev/null +++ b/src/static_sim/SimTargetOption.cpp @@ -0,0 +1,19 @@ +// +// Created by cflin on 4/17/23. +// +#include +#include "SimTargetOption.h" +namespace ssim{ + const std::string SimTargetOption::TAEGET_NAME[SimTargetOption::ENUM_SIZE] = { + "位移范数", + "位移-X", + "位移-Y", + "位移-Z", + "应力范数", + "冯氏应力", + "应力-X", + "应力-Y", + "应力-Z", + "柔顺度" + }; +}; \ No newline at end of file diff --git a/src/static_sim/SimTargetOption.h b/src/static_sim/SimTargetOption.h index 00cdcd2..5da9a8b 100644 --- a/src/static_sim/SimTargetOption.h +++ b/src/static_sim/SimTargetOption.h @@ -4,7 +4,7 @@ #ifndef RIGIDIPC_SIMTARGETOPTION_H #define RIGIDIPC_SIMTARGETOPTION_H - +#include namespace ssim { class SimTargetOption { @@ -12,6 +12,7 @@ namespace ssim { enum Target { U_NORM = 0, UX, UY, UZ, S_NORM, S_VON_Mises,/*primary stress*/SX, SY, SZ, COMPLIANCE, ENUM_SIZE }; + static const std::string TAEGET_NAME[ENUM_SIZE]; SimTargetOption(int init_state = 1) : state(init_state) {} diff --git a/src/viewer/ColorbarPlugin.cpp b/src/viewer/ColorbarPlugin.cpp new file mode 100644 index 0000000..cf8eeaf --- /dev/null +++ b/src/viewer/ColorbarPlugin.cpp @@ -0,0 +1,129 @@ +// +// Created by cflin on 4/17/23. +// + +#include "ColorbarPlugin.h" +#include + +namespace ssim { + + + void ColorbarPlugin::init_colormaps() { + auto texture_from_colormap = [](const Eigen::MatrixXd &rgb, GLuint &id) { + int width = 1; + int height = (int) rgb.rows(); + + Eigen::Matrix cmap; + if (rgb.maxCoeff() > 1.0) { + cmap = rgb.cast(); + } else { + cmap = (rgb.array() * 255.f).cast(); + } + assert(cmap.cols() == 3); + cmap.conservativeResize(cmap.rows(), 4); + cmap.col(3).setConstant(255); + + if (id == 0) { + glGenTextures(1, &id); + } + glBindTexture(GL_TEXTURE_2D, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, + width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, cmap.data()); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + }; + + Eigen::MatrixXd rgb; + for (size_t i = 0; i < igl::NUM_COLOR_MAP_TYPES; ++i) { + GLuint id = 0; + colormap(static_cast(i), Eigen::VectorXd::LinSpaced(100, 1, 0), false, rgb); + texture_from_colormap(rgb, id); + colormaps_[i] = id; + } + } + +// Draws a combo box for selecting the colormap + int ColorbarPlugin::draw_colormap_combo() const { + const char *items[]{ + "Inferno", + "Jet", + "Magma", + "Parula", + "Plasma", + "Viridis", + }; + static int selected_index = 1; + static const char *current_item = items[selected_index]; + ImVec2 combo_pos = ImGui::GetCursorScreenPos(); + if (ImGui::BeginCombo("Colormap##combo", "")) { + for (int n = 0; n < IM_ARRAYSIZE(items); ++n) { + // You can store your selection however you want, outside or inside your objects + bool is_selected = (current_item == items[n]); + ImGui::PushID(n); + if (ImGui::Selectable("", is_selected)) { + current_item = items[n]; + selected_index = n; + } + ImGui::SameLine(0, 0); + ImGui::Image( + reinterpret_cast(colormaps_[n]), + ImVec2(ImGui::GetTextLineHeight(), ImGui::GetTextLineHeight()), + ImVec2(0, 0), ImVec2(1, 1)); + ImGui::SameLine(); + ImGui::Text("%s", items[n]); + if (is_selected) { + ImGui::SetItemDefaultFocus(); + } + ImGui::PopID(); + } + ImGui::EndCombo(); + } + + ImVec2 backup_pos = ImGui::GetCursorScreenPos(); + ImGuiStyle &style = ImGui::GetStyle(); + ImGui::SetCursorScreenPos(ImVec2(combo_pos.x + style.FramePadding.x, combo_pos.y + style.FramePadding.y)); + float h = ImGui::GetTextLineHeight(); + ImGui::Image( + reinterpret_cast(colormaps_[selected_index]), + ImVec2(h, h)); + ImGui::SameLine(); + ImGui::Text("%s", current_item); + ImGui::SetCursorScreenPos(backup_pos); + + return selected_index; + } + +// Draws the actual colorbar with min/max values + void ColorbarPlugin::draw_colorbar(igl::ColorMapType cm, float xmin, float xmax, + const Eigen::Vector4f &background_color) const { + ImVec4 color(0, 0, 0, 1); +// auto rgb = background_color; +// // http://stackoverflow.com/a/3943023/112731 +// if (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114 > 186) { + color = ImVec4(1, 1, 1, 1); +// } + float w = 20; + float h = 200; + ImGui::BeginGroup(); + ImGui::BeginGroup(); + static const int num_interval=5; + static const float interval=(h - 1.0*(num_interval+1) * ImGui::GetTextLineHeightWithSpacing())/num_interval; + ImGui::TextColored(color, "%.3g", xmax); + + for(int i=num_interval-1;i>=0;--i){ + ImGui::Dummy(ImVec2(0, interval)); + ImGui::TextColored(color, "%.3g", (xmax-xmin)/num_interval*i+xmin); + } + + ImGui::EndGroup(); + ImGui::SameLine(); + ImGui::Image(reinterpret_cast(colormaps_[cm]), ImVec2(w, h)); + ImGui::EndGroup(); + } + +} // ssim \ No newline at end of file diff --git a/src/viewer/ColorbarPlugin.h b/src/viewer/ColorbarPlugin.h new file mode 100644 index 0000000..f39c4b4 --- /dev/null +++ b/src/viewer/ColorbarPlugin.h @@ -0,0 +1,36 @@ +// +// Created by cflin on 4/17/23. +// + +#ifndef EXAMPLE_COLORBARPLUGIN_H +#define EXAMPLE_COLORBARPLUGIN_H +#include +#include + +namespace ssim { + + class ColorbarPlugin { + public: + ColorbarPlugin(){ + init_colormaps(); + } + void draw_colorbar_jet(float xmin,float xmax){ + draw_colorbar(igl::COLOR_MAP_TYPE_JET,xmin,xmax, Eigen::Vector4f(0.9f, 0.9f, 0.9f, 0.4f)); + } + protected: + void init_colormaps(); + + int draw_colormap_combo() const; + + void draw_colorbar(igl::ColorMapType cm, float xmin, float xmax, + const Eigen::Vector4f &background_color) const; + + protected: + std::array colormaps_; + + igl::ColorMapType colormap_type_ = igl::COLOR_MAP_TYPE_JET; + }; + +} // ssim + +#endif //EXAMPLE_COLORBARPLUGIN_H diff --git a/src/viewer/StaticSimGUI.cpp b/src/viewer/StaticSimGUI.cpp index f89de35..de09a80 100644 --- a/src/viewer/StaticSimGUI.cpp +++ b/src/viewer/StaticSimGUI.cpp @@ -2,8 +2,9 @@ // Created by cflin on 4/14/23. // #include "StaticSimGUI.h" +#include "ColorbarPlugin.h" -namespace ssim{ +namespace ssim { void StaticSimGUI::viewer_launch() { auto config_viewer = [&] { @@ -30,8 +31,8 @@ namespace ssim{ return false; }; - menu_.callback_draw_viewer_window=[&](){ - float menu_width = 250.f *plugin_.hidpi_scaling() / plugin_.pixel_ratio(); + menu_.callback_draw_viewer_window = [&]() { + float menu_width = 250.f * plugin_.hidpi_scaling() / plugin_.pixel_ratio(); ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSizeConstraints(ImVec2(menu_width, -1.0f), ImVec2(menu_width, -1.0f)); @@ -43,11 +44,42 @@ namespace ssim{ ); ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f); // call menu here - menu_draw_viewer_menu(); + draw_menu(); ImGui::PopItemWidth(); ImGui::End(); + + if (!gui_ctrl_.is_single_color) { + + //--------------------------------window2: colorbar--------------------// +// float legends_width = 270.f * plugin_.hidpi_scaling(); +// +// ImGui::SetNextWindowSizeConstraints( +// ImVec2(200.0f, 30.0f), ImVec2(legends_width, -1.0f)); + + float menu_width = 100.f * plugin_.hidpi_scaling() / plugin_.pixel_ratio(); + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - menu_width, + ImGui::GetIO().DisplaySize.y - menu_width * 2), + ImGuiCond_FirstUseEver); + + ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(menu_width, -1.0f), ImVec2(menu_width, -1.0f)); + bool _viewer_menu_visible = true; + ImGui::Begin( + SimTargetOption::TAEGET_NAME[gui_ctrl_.target_to_evaluate].c_str(), + &_viewer_menu_visible, + ImGuiWindowFlags_NoSavedSettings + | ImGuiWindowFlags_AlwaysAutoResize + ); + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f); + // call menu here + draw_colorbar(); + ImGui::PopItemWidth(); + ImGui::End(); + } + }; + viewer_.launch( /*resizable=*/true, /*fullscreen=*/false, /*name=*/"静力学仿真"); @@ -103,6 +135,9 @@ namespace ssim{ C.row(NBC_vertex_idx(i_)) = Eigen::RowVector3d(1, 0, 0); } } + + gui_ctrl_.colorbar_bd.xmin = target.minCoeff(); + gui_ctrl_.colorbar_bd.xmax = target.maxCoeff(); viewer_.data_list[0].set_colors(C); } else { Eigen::MatrixXd color(V.rows(), 3); @@ -198,9 +233,9 @@ namespace ssim{ // size remain 1 viewer_.data_list.resize(1); viewer_.data_list.front().clear(); - viewer_.data_list.front().show_lines= true; + viewer_.data_list.front().show_lines = true; // add boundary box - for (int i = 1; i <=sp_StaticSim_->DirichletBCs.size() + sp_StaticSim_->NeumannBCs.size(); ++i) { + for (int i = 1; i <= sp_StaticSim_->DirichletBCs.size() + sp_StaticSim_->NeumannBCs.size(); ++i) { viewer_.append_mesh(); viewer_.data_list.back().show_lines = false; } diff --git a/src/viewer/StaticSimGUI.h b/src/viewer/StaticSimGUI.h index 8b6510d..c776964 100644 --- a/src/viewer/StaticSimGUI.h +++ b/src/viewer/StaticSimGUI.h @@ -19,6 +19,7 @@ #include #include "../static_sim/StaticSim.h" #include "StaticMenu.h" +#include "ColorbarPlugin.h" namespace ssim { @@ -30,6 +31,10 @@ namespace ssim { bool is_visible_BC = false; bool is_visible_mesh = true; bool is_single_color = true; + struct ColorbarBoundary{ + float xmin; + float xmax; + }colorbar_bd; ssim::SimTargetOption::Target target_to_evaluate = ssim::SimTargetOption::U_NORM; void set_target(ssim::SimTargetOption::Target target_to_set) { @@ -46,7 +51,7 @@ namespace ssim { void viewer_launch(); - protected: + private: void reload_json(std::string f_json=""); @@ -56,7 +61,21 @@ namespace ssim { void init_mesh(); - void menu_draw_viewer_menu(); + void draw_menu(); + + void draw_colorbar(){ + auto colorbar_menu=[&](){ + static ColorbarPlugin color_plugin; + color_plugin.draw_colorbar_jet(gui_ctrl_.colorbar_bd.xmin,gui_ctrl_.colorbar_bd.xmax); + }; + if (!gui_ctrl_.is_initialized && gui_ctrl_.is_loaded_json) { + if (gui_ctrl_.is_solved) { + if(!gui_ctrl_.is_single_color){ + colorbar_menu(); + } + } + } + } private: bool pre_draw_loop(); diff --git a/src/viewer/StaticSimGUIMenu.cpp b/src/viewer/StaticSimGUIMenu.cpp index a85d057..25dd944 100644 --- a/src/viewer/StaticSimGUIMenu.cpp +++ b/src/viewer/StaticSimGUIMenu.cpp @@ -4,9 +4,11 @@ #include #include "StaticSimGUI.h" #include "Util.h" -namespace ssim{ +#include "ColorbarPlugin.h" - void StaticSimGUI::menu_draw_viewer_menu() { +namespace ssim { + + void StaticSimGUI::draw_menu() { // Draw parent menu content // menu_.draw_viewer_menu(); @@ -14,19 +16,16 @@ namespace ssim{ 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; - } + if(f_json=="") return; + reload_json(f_json); #else - load(CMAKE_SOURCE_DIR "/sim-test/rigid-test/rocker-arm/config.json"); + reload_json(CMAKE_SOURCE_DIR "/sim-test/rigid-test/cube/config.json"); #endif + gui_ctrl_.is_initialized = true; + gui_ctrl_.is_loaded_json = true; } - - }; auto model_menu = [&]() { @@ -133,85 +132,84 @@ namespace ssim{ 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)) { + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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 v_is_extract(arr_extract,arr_extract+SimTargetOption::Target::ENUM_SIZE); - sp_StaticSim_->ExtractTarget(extract_dir,v_is_extract,is_extract_coord); + 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 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); + ImGui::Checkbox("导出坐标", &is_extract_coord); }; - if (ImGui::CollapsingHeader("载入模型", ImGuiTreeNodeFlags_DefaultOpen)) { io_menu(); } diff --git a/src/viewer/Util.h b/src/viewer/Util.h index 08226e8..5f849a6 100644 --- a/src/viewer/Util.h +++ b/src/viewer/Util.h @@ -7,7 +7,7 @@ #include #include #include - +#include #ifdef _WIN32 #include #include @@ -111,6 +111,39 @@ namespace ssim { return std::string(buffer); } + void texture_from_colormap(const Eigen::MatrixXd &rgb, GLuint & id) + { + int width = 1; + int height = (int) rgb.rows(); + + Eigen::Matrix cmap; + if (rgb.maxCoeff() > 1.0) { + cmap = rgb.cast(); + } else { + cmap = (rgb.array() * 255.f).cast(); + } + assert(cmap.cols() == 3); + cmap.conservativeResize(cmap.rows(), 4); + cmap.col(3).setConstant(255); + + if (id == 0) { + glGenTextures(1, &id); + } + glBindTexture(GL_TEXTURE_2D, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, + width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, cmap.data()); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + } + + + + } // ssim #endif //EXAMPLE_UTIL_H