#include "viz/gauge.h" #include "imgui.h" #include #include #ifndef M_PI #define M_PI 3.14159265358979323846f #endif void gauge(const char* label, float value, float min_val, float max_val, float radius) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImVec2 pos = ImGui::GetCursorScreenPos(); // Reserve space: diameter + label line float diameter = radius * 2.0f; ImGui::Dummy(ImVec2(diameter, diameter + ImGui::GetTextLineHeightWithSpacing())); ImVec2 center = ImVec2(pos.x + radius, pos.y + radius); // Arc spans 240 degrees: from 150deg to 390deg (i.e. 150 to 30 going clockwise) // In screen space Y is down, so angles go clockwise. // Start angle: 150 degrees = bottom-left, End angle: 390 = 30 degrees = bottom-right const float angle_start = (150.0f * (float)M_PI) / 180.0f; const float angle_end = (390.0f * (float)M_PI) / 180.0f; const int num_segments = 64; // Background arc (dark gray) ImU32 bg_color = IM_COL32(60, 60, 60, 220); for (int i = 0; i < num_segments; i++) { float a0 = angle_start + (angle_end - angle_start) * ((float)i / num_segments); float a1 = angle_start + (angle_end - angle_start) * ((float)(i + 1) / num_segments); draw_list->AddLine( ImVec2(center.x + cosf(a0) * radius, center.y + sinf(a0) * radius), ImVec2(center.x + cosf(a1) * radius, center.y + sinf(a1) * radius), bg_color, 6.0f); } // Normalize value to [0, 1] float t = 0.0f; if (max_val > min_val) { t = (value - min_val) / (max_val - min_val); if (t < 0.0f) t = 0.0f; if (t > 1.0f) t = 1.0f; } // Color: green (t=0) -> yellow (t=0.5) -> red (t=1) float r, g, b; if (t < 0.5f) { float s = t * 2.0f; r = (unsigned char)(s * 255); g = 200; b = 0; } else { float s = (t - 0.5f) * 2.0f; r = 220; g = (unsigned char)((1.0f - s) * 200); b = 0; } ImU32 value_color = IM_COL32((int)r, (int)g, (int)b, 255); // Value arc float angle_value = angle_start + (angle_end - angle_start) * t; int value_segments = (int)(num_segments * t); for (int i = 0; i < value_segments; i++) { float a0 = angle_start + (angle_end - angle_start) * ((float)i / num_segments); float a1 = angle_start + (angle_end - angle_start) * ((float)(i + 1) / num_segments); draw_list->AddLine( ImVec2(center.x + cosf(a0) * radius, center.y + sinf(a0) * radius), ImVec2(center.x + cosf(a1) * radius, center.y + sinf(a1) * radius), value_color, 6.0f); } // Needle: line from center to arc at current angle float needle_len = radius * 0.75f; ImVec2 needle_tip = ImVec2( center.x + cosf(angle_value) * needle_len, center.y + sinf(angle_value) * needle_len); draw_list->AddLine(center, needle_tip, IM_COL32(255, 255, 255, 240), 2.0f); draw_list->AddCircleFilled(center, 4.0f, IM_COL32(255, 255, 255, 200)); // Value text centered char val_buf[32]; snprintf(val_buf, sizeof(val_buf), "%.1f", value); ImVec2 val_size = ImGui::CalcTextSize(val_buf); draw_list->AddText( ImVec2(center.x - val_size.x * 0.5f, center.y + radius * 0.35f), IM_COL32(230, 230, 230, 255), val_buf); // Label below value ImVec2 label_size = ImGui::CalcTextSize(label); draw_list->AddText( ImVec2(center.x - label_size.x * 0.5f, center.y + radius * 0.35f + val_size.y + 2.0f), IM_COL32(180, 180, 180, 200), label); }