Skip to content

Commit

Permalink
app: adds multiple plots in simulation editor
Browse files Browse the repository at this point in the history
  • Loading branch information
quesnel committed Jun 10, 2024
1 parent 7bcdaca commit 5b3a8f5
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 94 deletions.
11 changes: 5 additions & 6 deletions app/gui/plot-observation-widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,13 @@ void plot_observation_widget::show(application& app) noexcept
ImPlotAxisFlags_AutoFit,
ImPlotAxisFlags_AutoFit);

v_obs.for_each_obs([&](const auto obs_id,
const auto /*color*/,
const auto option,
const auto& name) noexcept {
auto* obs = app.sim.observers.try_to_get(obs_id);
v_obs.for_each([&](const auto id) noexcept {
const auto idx = get_index(id);
const auto obs_id = v_obs.get_obs_ids()[idx];
auto* obs = app.sim.observers.try_to_get(obs_id);

if (obs->linearized_buffer.size() > 0) {
switch (option) {
switch (v_obs.get_options()[idx]) {
case variable_observer::type_options::line:
ImPlot::PlotLineG(name.c_str(),
ring_buffer_getter,
Expand Down
121 changes: 49 additions & 72 deletions app/gui/simulation-editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,23 +355,10 @@ static bool show_local_simulation_plot_observers_table(application& app,
{
debug::ensure(!component_is_grid_or_graph(app.mod, tn));

if (not app.pj.variable_observers.can_alloc()) {
ImGui::TextFormatDisabled(
"Not enough variable observers memory available (default: {})",
app.pj.variable_observers.capacity());
return false;
}

auto is_modified = 0;

if (ImGui::CollapsingHeader("Plot observers",
ImGuiTreeNodeFlags_DefaultOpen)) {

ImGui::BeginChild("c-show-plot",
ImVec2(ImGui::GetContentRegionAvail().x, 260.f),
ImGuiChildFlags_None,
ImGuiWindowFlags_HorizontalScrollbar);

if (ImGui::BeginTable("Observation table", 4)) {
ImGui::TableSetupColumn("enable");
ImGui::TableSetupColumn("name");
Expand Down Expand Up @@ -459,22 +446,26 @@ static bool show_local_simulation_plot_observers_table(application& app,
ImGui::TableNextColumn();

if (enable) {
const auto old_current = vobs_id;
if (select_variable_observer(app.pj, vobs_id)) {
if (old_current != vobs_id) {
if_data_exists_do(app.pj.variable_observers,
old_current,
[&](auto& v_obs) noexcept {
v_obs.erase(tn_id, mdl_id);
});

const auto old_vobs_id = vobs_id;
if (select_variable_observer(app.pj, vobs_id) and
old_vobs_id != vobs_id) {
auto* o =
app.pj.variable_observers.try_to_get(old_vobs_id);
auto* n = app.pj.variable_observers.try_to_get(vobs_id);

if (o and n) {
const auto old_sub_id = o->find(tn_id, mdl_id);
auto new_sub_id = n->push_back(tn_id, mdl_id);

n->get_colors()[get_index(new_sub_id)] =
o->get_colors()[get_index(old_sub_id)];
n->get_options()[get_index(new_sub_id)] =
o->get_options()[get_index(old_sub_id)];
n->get_names()[get_index(new_sub_id)] =
o->get_names()[get_index(old_sub_id)];

o->erase(tn_id, mdl_id);
tn.variable_observer_ids.set(uid, vobs_id);
if_data_exists_do(app.pj.variable_observers,
vobs_id,
[&](auto& v_obs) noexcept {
v_obs.push_back(tn_id,
mdl_id);
});
}
}
} else {
Expand All @@ -488,8 +479,6 @@ static bool show_local_simulation_plot_observers_table(application& app,

ImGui::EndTable();
}

ImGui::EndChild();
}

return is_modified > 0;
Expand Down Expand Up @@ -621,41 +610,37 @@ static bool show_local_simulation_specific_observers(application& app,
}

static void show_local_variables_plot(application& app,
variable_observer& v_obs) noexcept
variable_observer& v_obs,
tree_node_id tn_id) noexcept
{
v_obs.for_each_obs([&](const auto obs_id,
const auto /*color*/,
const auto option,
const auto& name) noexcept {
if (auto* obs = app.sim.observers.try_to_get(obs_id); obs)
show_local_variable_plot(*obs, name, option);
v_obs.for_each([&](const auto id) noexcept {
const auto idx = get_index(id);
auto* obs = app.sim.observers.try_to_get(v_obs.get_obs_ids()[idx]);

if (obs and v_obs.get_tn_ids()[idx] == tn_id)
show_local_variable_plot(
*obs, v_obs.get_names()[idx], v_obs.get_options()[idx]);
});
}

static void show_local_variable_observers(application& app,
tree_node& tn) noexcept
{
if (ImPlot::BeginPlot("variables", ImVec2(-1, 200))) {
ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 1.f);
ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 1.f);

auto i = 0;

while (i != tn.variable_observer_ids.data.ssize()) {
auto v_obs_id = tn.variable_observer_ids.data[i].value;
auto* v_obs = app.pj.variable_observers.try_to_get(v_obs_id);

if (v_obs) {
show_local_variables_plot(app, *v_obs);
++i;
} else {
tn.variable_observer_ids.data.swap_pop_back(i);
tn.variable_observer_ids.sort();
for (auto& vobs : app.pj.variable_observers) {
const auto tn_id = app.pj.tree_nodes.get_id(tn);
if (vobs.exists(tn_id)) {
ImGui::PushID(&vobs);
if (ImPlot::BeginPlot(vobs.name.c_str(), ImVec2(-1, 200))) {
ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 1.f);
ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 1.f);

show_local_variables_plot(app, vobs, tn_id);

ImPlot::PopStyleVar(2);
ImPlot::EndPlot();
}
ImGui::PopID();
}

ImPlot::PopStyleVar(2);
ImPlot::EndPlot();
}
}

Expand Down Expand Up @@ -814,11 +799,6 @@ static bool show_simulation_table_variable_observers(application& app) noexcept
auto to_delete = undefined<variable_observer_id>();
bool is_modified = false;

ImGui::BeginChild("c-show-table-plot",
ImVec2(ImGui::GetContentRegionAvail().x, 260.f),
ImGuiChildFlags_None,
ImGuiWindowFlags_HorizontalScrollbar);

if (not app.pj.variable_observers.can_alloc(1))
ImGui::TextFormatDisabled(
"Can not allocate more multi-plot observers (max reached: {})",
Expand Down Expand Up @@ -867,18 +847,16 @@ static bool show_simulation_table_variable_observers(application& app) noexcept
ImGui::PopID();
});

if (app.pj.variable_observers.can_alloc(1)) {
ImGui::TableNextColumn();
if (ImGui::Button("+")) {
auto& v = app.pj.variable_observers.alloc();
v.name = "New";
}
}

ImGui::EndTable();
}

ImGui::EndChild();
if (app.pj.variable_observers.can_alloc(1)) {
if (ImGui::Button("+")) {
auto& v = app.pj.variable_observers.alloc();
v.name = "New";
is_modified = true;
}
}

if (is_defined(to_delete)) {
app.pj.variable_observers.free(to_delete);
Expand Down Expand Up @@ -959,8 +937,7 @@ static bool show_project_observations(application& app) noexcept

auto updated = 0;

if (not app.pj.variable_observers.empty() &&
ImGui::CollapsingHeader("Plots", flags))
if (ImGui::CollapsingHeader("Plots", flags))
updated += show_simulation_table_variable_observers(app);

if (not app.pj.grid_observers.empty() &&
Expand Down
97 changes: 83 additions & 14 deletions lib/include/irritator/modeling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,7 @@ class variable_observer

//! @brief Search a `sub_id` `tn` and `mdl`.
sub_id find(const tree_node_id tn, const model_id mdl) noexcept;
bool exists(const tree_node_id tn) noexcept;

//! @brief Remove `sub_id` for all ` m_tn_ids` equal to `tn` and `mdl_ids`
//! equal to `mdl`.
Expand All @@ -1154,32 +1155,36 @@ class variable_observer
template<typename Function>
void if_exists_do(const sub_id id, Function&& fn) noexcept
{
if (m_ids.exists(id)) {
const auto idx = get_index(id);

fn(m_obs_ids[idx], m_colors[idx], m_options[idx], m_names[idx]);
}
if (m_ids.exists(id))
fn(id);
}

template<typename Function>
void for_each_tn_mdl(Function&& f) const noexcept
void for_each(Function&& f) noexcept
{
for (const auto id : m_ids)
f(m_tn_ids[get_index(id)], m_mdl_ids[get_index(id)]);
f(id);
}

template<typename Function>
void for_each_obs(Function&& f) const noexcept
void for_each(Function&& f) const noexcept
{
for (const auto id : m_ids)
f(m_obs_ids[get_index(id)],
m_colors[get_index(id)],
m_options[get_index(id)],
m_names[get_index(id)]);
f(id);
}

std::span<name_str> get_names() noexcept { return m_names; }
std::span<const name_str> get_names() const noexcept { return m_names; }
std::span<tree_node_id> get_tn_ids() noexcept;
std::span<const tree_node_id> get_tn_ids() const noexcept;
std::span<model_id> get_mdl_ids() noexcept;
std::span<const model_id> get_mdl_ids() const noexcept;
std::span<observer_id> get_obs_ids() noexcept;
std::span<const observer_id> get_obs_ids() const noexcept;
std::span<name_str> get_names() noexcept;
std::span<const name_str> get_names() const noexcept;
std::span<color> get_colors() noexcept;
std::span<const color> get_colors() const noexcept;
std::span<type_options> get_options() noexcept;
std::span<const type_options> get_options() const noexcept;
};

struct log_entry {
Expand Down Expand Up @@ -1626,6 +1631,70 @@ inline child::child(component_id component) noexcept
, type{ child_type::component }
{}

inline std::span<tree_node_id> variable_observer::get_tn_ids() noexcept
{
return m_tn_ids;
}

inline std::span<const tree_node_id> variable_observer::get_tn_ids()
const noexcept
{
return m_tn_ids;
}

inline std::span<model_id> variable_observer::get_mdl_ids() noexcept
{
return m_mdl_ids;
}

inline std::span<const model_id> variable_observer::get_mdl_ids() const noexcept
{
return m_mdl_ids;
}

inline std::span<observer_id> variable_observer::get_obs_ids() noexcept
{
return m_obs_ids;
}

inline std::span<const observer_id> variable_observer::get_obs_ids()
const noexcept
{
return m_obs_ids;
}

inline std::span<name_str> variable_observer::get_names() noexcept
{
return m_names;
}

inline std::span<const name_str> variable_observer::get_names() const noexcept
{
return m_names;
}

inline std::span<color> variable_observer::get_colors() noexcept
{
return m_colors;
}

inline std::span<const color> variable_observer::get_colors() const noexcept
{
return m_colors;
}

inline std::span<variable_observer::type_options>
variable_observer::get_options() noexcept
{
return m_options;
}

inline std::span<const variable_observer::type_options>
variable_observer::get_options() const noexcept
{
return m_options;
}

inline tree_node::tree_node(component_id id_, u64 unique_id_) noexcept
: id(id_)
, unique_id(unique_id_)
Expand Down
8 changes: 6 additions & 2 deletions lib/src/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6274,9 +6274,13 @@ static status do_project_save_plot_observations(Writer& w, project& pj) noexcept
w.Key("name");
w.String(plot.name.begin(), plot.name.size());

plot.for_each_tn_mdl([&](const auto tn_id, const auto mdl_id) noexcept {
plot.for_each([&](const auto id) noexcept {
const auto idx = get_index(id);
const auto tn = plot.get_tn_ids()[idx];
const auto mdl = plot.get_mdl_ids()[idx];

w.Key("access");
pj.build_unique_id_path(tn_id, mdl_id, path);
pj.build_unique_id_path(tn, mdl, path);
write_project_unique_id_path(w, path);
});

Expand Down
12 changes: 12 additions & 0 deletions lib/src/variable-observer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ auto variable_observer::find(const tree_node_id tn,
return undefined<variable_observer::sub_id>();
}

bool variable_observer::exists(const tree_node_id tn) noexcept
{
for (const auto id : m_ids) {
const auto idx = get_index(id);

if (m_tn_ids[idx] == tn)
return true;
}

return false;
}

void variable_observer::erase(const tree_node_id tn,
const model_id mdl) noexcept
{
Expand Down

0 comments on commit 5b3a8f5

Please sign in to comment.