EchoMap 2026-07-25 6d3977c
An experimental cross-platform digital signal processing application for sound-source localisation.
Loading...
Searching...
No Matches
SensorGeometryPanel.cpp
Go to the documentation of this file.
1
7
9
10#include "../EchoMap.hpp"
12#include "../objects/Project.hpp"
13#include "../objects/Sensor.hpp"
14#include "../utility/Logger.hpp"
15
16namespace echomap
17{
18
20 EchoMap* app,
21 const Project* const initial_project
22) :
23 panel_name(std::string("Sensor Geometry") + get_imgui_stable_name()),
24 active_project(initial_project),
25 app(app)
26{
27}
28
29const char* SensorGeometryPanel::get_imgui_name() const noexcept
30{
31 return panel_name.c_str();
32}
33
35{
36 if (ImGui::Begin(panel_name.c_str())) {
37 if (active_project == nullptr)
38 ImGui::Text("No project is loaded.");
39 else if (active_project->get_sensors_count() == 0u)
40 ImGui::Text("No sensors are loaded.");
41 else {
42 recache_sensor_colours();
43 draw_geometry_summary();
44 draw_geometry_plot();
45 }
46 }
47
48 ImGui::End();
49}
50
52 const Project* const new_project
53)
54{
55 active_project = new_project;
56 sensor_colours.clear();
57}
58
59const char* SensorGeometryPanel::get_imgui_stable_name() noexcept
60{
61 return "###SensorGeometryPanel";
62}
63
64void SensorGeometryPanel::recache_sensor_colours() noexcept
65{
66 if (active_project->get_sensors_count() != sensor_colours.size()) {
67 // Ensure that we maintain the correct number of colours for the current number of sensors.
68 try {
69 sensor_colours.resize(active_project->get_sensors_count());
70 for (auto [src, dst] : std::views::zip(active_project->observe_sensors(), sensor_colours))
71 dst = IM_COL32(
72 static_cast<int>(src.colour.r * 255.0f),
73 static_cast<int>(src.colour.g * 255.0f),
74 static_cast<int>(src.colour.b * 255.0f),
75 static_cast<int>(src.colour.a * 255.0f)
76 );
77 } catch (const std::exception& exception) {
78 LOG_F_ERROR("Could not store the sensor colouring: {}", exception.what());
79 plotting_spec_3d.MarkerFillColors = nullptr;
80 plotting_spec_3d.MarkerLineColors = nullptr;
81 plotting_spec_3d.MarkerFillColor = ImVec4(255.0f, 255.0f, 255.0f, 255.0f);
82 plotting_spec_3d.MarkerLineColor = IMPLOT_AUTO_COL;
83 return;
84 }
85
86 // ... and update the plotting specification in case the resize invalidated pointers.
87 plotting_spec_3d.MarkerFillColors = &*sensor_colours.begin();
88 plotting_spec_3d.MarkerLineColors = plotting_spec_3d.MarkerFillColors;
89 }
90}
91
92void SensorGeometryPanel::draw_geometry_summary() noexcept
93{
94 ImGui::SeparatorText("Geometry Summary");
95 if (ImGui::BeginTable("##GeometrySummary", 5, table_flags)) {
96 ImGui::TableSetupColumn("##SensorColourColumn", ImGuiTableColumnFlags_WidthFixed);
97 ImGui::TableSetupColumn("Sensor", ImGuiTableColumnFlags_WidthFixed);
98 ImGui::TableSetupColumn("X Position", ImGuiTableColumnFlags_WidthStretch);
99 ImGui::TableSetupColumn("Y Position", ImGuiTableColumnFlags_WidthStretch);
100 ImGui::TableSetupColumn("Z Position", ImGuiTableColumnFlags_WidthStretch);
101 ImGui::TableHeadersRow();
102
103 std::size_t row_idx = 0;
104
105 for (const auto& sensor : active_project->observe_sensors()) {
106 ImGui::PushID(static_cast<int>(sensor.get_id()));
107
108 ImGui::TableNextRow();
109 ImGui::TableNextColumn();
110
111 const ImVec4 colour = ImGui::ColorConvertU32ToFloat4(sensor_colours[row_idx]);
112 std::array<float, 4> new_colour = {colour.x, colour.y, colour.z, colour.w};
113 if (ImGui::ColorEdit4("##colour", new_colour.data(), ImGuiColorEditFlags_NoInputs)) {
114 app->notify(ModifySensorColourNotification(
115 active_project->get_id(),
116 sensor.get_id(),
117 {
118 .r = new_colour[0],
119 .g = new_colour[1],
120 .b = new_colour[2],
121 .a = new_colour[3],
122 }
123 ));
124
125 sensor_colours[row_idx] = IM_COL32(
126 static_cast<int>(new_colour[0] * 255.0f),
127 static_cast<int>(new_colour[1] * 255.0f),
128 static_cast<int>(new_colour[2] * 255.0f),
129 static_cast<int>(new_colour[3] * 255.0f)
130 );
131 }
132
133 ImGui::TableNextColumn();
134 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
135 ImGui::TextUnformatted(sensor.get_imgui_name());
136
137 Position new_position = sensor.position;
138 bool position_changed = false;
139
140 ImGui::TableNextColumn();
141 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
142 position_changed = ImGui::InputFloat("##x", &new_position.x, 0.01f, 1.0f);
143
144 ImGui::TableNextColumn();
145 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
146 position_changed = ImGui::InputFloat("##y", &new_position.y, 0.01f, 1.0f) || position_changed;
147
148 ImGui::TableNextColumn();
149 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
150 position_changed = ImGui::InputFloat("##z", &new_position.z, 0.01f, 1.0f) || position_changed;
151
152 ImGui::PopID();
153 ++row_idx;
154
155 if (position_changed)
156 app->notify(ModifySensorPositionNotification(active_project->get_id(), sensor.get_id(), new_position));
157 }
158
159 ImGui::EndTable();
160 }
161}
162
163void SensorGeometryPanel::draw_geometry_plot() const noexcept
164{
165 ImGui::SeparatorText("Geometry Plot");
166 ImPlot3D::PushStyleColor(ImPlot3DCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
167
168 const auto avail_size = ImGui::GetContentRegionAvail();
169 const float aspect_ratio = avail_size.x / avail_size.y;
170
171 if (ImPlot3D::BeginPlot("##SensorGeometryPlot", ImVec2(-std::numeric_limits<float>::min(), avail_size.y))) {
172 ImPlot3D::SetupBoxScale(aspect_ratio, 1.0f, 1.0f);
173 ImPlot3D::SetupAxes("X", "Y", "Z");
174 ImPlot3D::PlotScatterG(
175 "",
176 Project::get_sensor_point,
177 active_project,
178 static_cast<int>(active_project->get_sensors_count()),
179 plotting_spec_3d
180 );
181
182 ImPlot3D::EndPlot();
183 }
184
185 ImPlot3D::PopStyleColor();
186}
187
188} // namespace echomap
AllNotifications specification.
EchoMap class specification.
EchoMap portable logger specification.
#define LOG_F_ERROR(msg,...)
Logs a formatted error-level message using echomap::Logger::log_f.
Definition Logger.hpp:125
EchoMap sensor geometry panel specification.
The EchoMap maintains state for the application including WebGPU and Dear ImGui context,...
Definition EchoMap.hpp:35
auto observe_sensors() const noexcept
Provides a transformed view for stored Sensor objects in the Project.
Definition Project.hpp:137
size_t get_sensors_count() const noexcept
Checks if any Sensor objects are owned by the Project.
Definition Project.cpp:82
SensorGeometryPanel(EchoMap *app, const Project *initial_project=nullptr)
Create a new SensorGeometryPanel to plot and control Sensor information.
const char * get_imgui_name() const noexcept override
Retrieves the name of the IPanel for Dear ImGui API functions.
void change_active_project(const Project *new_project) override
Updates the active Project being described by the IPanel.
void draw() noexcept override
Draw the panel to the active rendering context.
T data(T... args)
T min(T... args)
The main EchoMap outermost namespace for all non-exported symbols.
STL namespace.
T resize(T... args)
T size(T... args)
T what(T... args)