はじめに
第2回ではポストプロセッサーとしてx-yグラフを表示したいと思います。
有限要素解析としては土-水連成解析を対象としています。
土-水連成解析の概要は以下をご覧ください。
やったこと
結果をX-Yグラフで出力させた
現時点で以下のようなGUIが完成しました。
プログラムの構成を作った
今のところ以下のような構造にしています
.
└── src
├── data
│ └── result.rs
├── post
│ └── plot.rs
├── app.rs
├── data.rs
├── lib.rs
├── main.rs
└── post.rs
main.rs: GUIの呼び出し
app.rs: GUIのデザインを構成
result.rs: 結果ファイル(.csv)を読み込み
plot.rs: 結果をグラフとして表示
苦労したところ
Hello world表示
あるあるかもしれませんが、GUI画面上で「Hello World」を表示させるまでにだいぶ時間がかかりました。
最初は前節で示した構成ではなくmain.rsだけで以下のように試しました。
use eframe::egui;
#[derive(Default)]
struct MyApp {}
impl eframe::App for MyApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("GeoGEN");
ui.label("Hello GeoGEN!");
});
}
}
fn main() -> eframe::Result<()> {
let options = eframe::NativeOptions::default();
eframe::run_native(
"GeoGEN GUI",
options,
Box::new(|_cc| Ok(Box::new(MyApp::default()))),
)
}
ちなみにGeoGENは今開発中のFEMプログラムの仮称です。
画面がダークモードになる
eguiでは画面がOSのダーク/ライトモードに引っ張られるようです。
画面を表示してみると、ダークモードになり非常に見にくかったです。
強制的にライトモードにするには以下のようにCentralPanelで包んでやる必要があります。
これを実装するまでにかなり時間を要しました。
impl eframe::App for MyApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
ui.ctx().set_visuals(egui::Visuals::light());
egui::CentralPanel::default().show_inside(ui, |ui| {
self.draw_header(ui);
ui.separator();
self.draw_controls(ui);
ui.separator();
if let Some(message) = &self.error_message {
ui.colored_label(egui::Color32::RED, message);
ui.separator();
}
draw_plot(ui, &self.cases, self.plot_type);
});
}
}
グラフの出力
第2回の肝です。
最初はこのような感じでグラフ出力しました。
まず、MyAPPにデータを持たせます。
struct MyApp {
data: Vec<ElementResult>,
}
次にボタンクリックしてcsv選択→読み込み→指定した変数をグラフとして出力するまでを実装しました。
impl eframe::App for MyApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("GeoGEN");
ui.label("Hello GeoGEN!");
let btn = ui.add(egui::Button::new(
egui::RichText::new("Open CSV").size(16.0),
));
if btn.clicked() {
if let Some(path) = rfd::FileDialog::new()
.add_filter("CSV", &["csv"])
.pick_file()
{
match read_csv(&path) {
Ok(data) => {
self.data = data;
}
Err(e) => {
eprintln!("CSV read error: {}", e);
}
}
}
}
for row in self.data.iter().take(5) {
ui.label(format!(
"step={} p'={} q={}",
row.step, row.mean_effective_stress, row.deviatoric_stress
));
}
});
}
}
fn read_csv(path: &Path) -> Result<Vec<ElementResult>, Box<dyn Error>> {
let mut reader = csv::Reader::from_path(path)?;
let mut data = Vec::new();
for result in reader.deserialize() {
let row: ElementResult = result?;
data.push(row);
}
Ok(data)
}
