Browse Source

add extract interface

master
cflin 2 years ago
parent
commit
8a529d4a99
  1. 20
      src/static_sim/StaticSim.h
  2. 184
      src/viewer/StaticSimGUI.cpp
  3. 26
      src/viewer/StaticSimGUI.h
  4. 233
      src/viewer/StaticSimGUIMenu.cpp
  5. 116
      src/viewer/Util.h

20
src/static_sim/StaticSim.h

@ -31,6 +31,7 @@ namespace ssim {
class StaticSimGUI; class StaticSimGUI;
} }
namespace ssim { namespace ssim {
struct Model { struct Model {
Eigen::MatrixX3d V; Eigen::MatrixX3d V;
Eigen::MatrixX3i F; Eigen::MatrixX3i F;
@ -79,6 +80,25 @@ namespace ssim {
void postprocess(Eigen::MatrixXd &Q, void postprocess(Eigen::MatrixXd &Q,
Eigen::VectorXd &QU, Eigen::VectorXd &QU,
Eigen::MatrixXd &Qstress); Eigen::MatrixXd &Qstress);
/// Extract data to save directory
/// \param save_dir absolute address, like "path/to/save_dir"
/// \param v_is_extract if (v_is_extract[i]){ extract the target i; }
/// \param extract_coord_flg
void ExtractTarget(std::string save_dir,std::vector<bool> v_is_extract,bool extract_coord_flg){
if(extract_coord_flg){
// TODO: add coordinate cols
spdlog::info("extract {}","coordinate");
}
for(int i=0;i<v_is_extract.size();++i){
assert(i<SimTargetOption::Target::ENUM_SIZE);
if(v_is_extract[i]){
// TODO: add #target col
spdlog::info("extract {}",i);
}
}
// TODO: extract the file
}
Eigen::MatrixXd EvaluateTarget(SimTargetOption::Target target) { Eigen::MatrixXd EvaluateTarget(SimTargetOption::Target target) {
if (!option_.is_option_set(target) || map_target_to_evaluated_[target].size()==0) { if (!option_.is_option_set(target) || map_target_to_evaluated_[target].size()==0) {

184
src/viewer/StaticSimGUI.cpp

@ -192,176 +192,30 @@ namespace ssim{
return false; return false;
} }
void StaticSimGUI::menu_draw_viewer_menu() {
// Draw parent menu content
// menu_.draw_viewer_menu();
auto io_menu = [&]() { void StaticSimGUI::init_mesh() {
if (ImGui::Button("加载文件##IO", ImVec2(-1, 0))) { // clear all data
#ifndef DEBUG_SSIM // size remain 1
std::string f_json = igl::file_dialog_open(); viewer_.data_list.resize(1);
if (f_json != "" ) { viewer_.data_list.front().clear();
reload_json(f_json); viewer_.data_list.front().show_lines= true;
gui_ctrl_.is_initialized = true; // add boundary box
gui_ctrl_.is_loaded_json = true; for (int i = 1; i <=sp_StaticSim_->DirichletBCs.size() + sp_StaticSim_->NeumannBCs.size(); ++i) {
viewer_.append_mesh();
viewer_.data_list.back().show_lines = false;
} }
#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, void StaticSimGUI::reload_json(std::string f_json) {
"%.3f"); sp_StaticSim_ = f_json == "" ? nullptr : std::make_shared<StaticSim>(ssim::SimTargetOption(), f_json);
ImGui::InputFloat("泊松比", &sp_StaticSim_->get_material_property().Poisson_ratio, 0.01f, 1.0f, gui_ctrl_ = GUICtrl();
"%.3f"); init_mesh();
ImGui::InputFloat("密度", &sp_StaticSim_->get_material_property().density, 1.0f, 1000.0f, "%.3f"); init_screen();
}
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));
if (ImGui::Button("位移范数", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::U_NORM);
}
if (ImGui::Button("位移-X", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::UX);
}
if (ImGui::Button("位移-Y", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::UY);
}
if (ImGui::Button("位移-Z", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::UZ);
}
if (ImGui::Button("应力范数", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::S_NORM);
}
if (ImGui::Button("冯氏应力", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::S_VON_Mises);
}
if (ImGui::Button("应力-X", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::SX);
}
if (ImGui::Button("应力-Y", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::SY);
}
if (ImGui::Button("应力-Z", ImVec2(-1, 0))) {
gui_ctrl_.set_target(ssim::SimTargetOption::Target::SZ);
}
};
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();
}
}
} }
StaticSimGUI::StaticSimGUI() {
viewer_.plugins.push_back(&plugin_);
plugin_.widgets.push_back(&menu_);
init_screen();
} }
} }

26
src/viewer/StaticSimGUI.h

@ -42,39 +42,19 @@ namespace ssim {
class StaticSimGUI { class StaticSimGUI {
public: public:
StaticSimGUI() { StaticSimGUI();
viewer_.plugins.push_back(&plugin_);
plugin_.widgets.push_back(&menu_);
init_screen();
}
void viewer_launch(); void viewer_launch();
protected: protected:
void reload_json(std::string f_json="") { void reload_json(std::string f_json="");
sp_StaticSim_ = f_json == "" ? nullptr : std::make_shared<StaticSim>(ssim::SimTargetOption(), f_json);
gui_ctrl_ = GUICtrl();
init_mesh();
init_screen();
}
void init_screen() { void init_screen() {
viewer_.core().background_color << 0.9f, 0.9f, 0.9f, 0.4f; viewer_.core().background_color << 0.9f, 0.9f, 0.9f, 0.4f;
} }
void init_mesh() { void init_mesh();
// clear all data
// size remain 1
viewer_.data_list.resize(1);
viewer_.data_list.front().clear();
viewer_.data_list.front().show_lines= true;
// add boundary box
for (int i = 1; i <=sp_StaticSim_->DirichletBCs.size() + sp_StaticSim_->NeumannBCs.size(); ++i) {
viewer_.append_mesh();
viewer_.data_list.back().show_lines = false;
}
}
void menu_draw_viewer_menu(); void menu_draw_viewer_menu();

233
src/viewer/StaticSimGUIMenu.cpp

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

116
src/viewer/Util.h

@ -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…
Cancel
Save