web UI added and refactoring done

This commit is contained in:
Ayzen
2026-06-06 00:06:30 +03:00
parent 3c30a12d4a
commit af6005d68f
65 changed files with 3630 additions and 4720 deletions
@@ -76,6 +76,12 @@ struct ProcessingLiveConfig {
float legacy_gpr_min_visible_pair_count = 0.0F;
std::uint32_t gpr_max_detected_objects_to_draw = 0;
std::uint32_t gpr_draw_top_m_objects = 0;
// Visible X/Z window (metres). The locator clips broadcast objects to this
// window so the socket emits only what the desktop plot actually shows.
float gpr_visible_x_min_m = -2.0F;
float gpr_visible_x_max_m = 2.0F;
float gpr_visible_z_min_m = 0.0F;
float gpr_visible_z_max_m = 14.0F;
// When true, the data_processor ignores socket-supplied `vlc` updates and
// keeps using `gpr_speed_m_s` from this file. Mirrored from the GUI's
// "ignore socket speed" checkbox.
@@ -64,6 +64,7 @@ void DataProcessor::run(const std::atomic<bool>& stop_requested) {
std::uint64_t last_replayed_revision = live_config_loader_.revision();
std::uint64_t last_applied_history_command_seq = 0;
std::uint64_t error_count = 0;
std::uint64_t consecutive_errors = 0;
// Fix #55: track the socket-fed speed used for the last reprocess so a change
// arriving without a live-config revision bump still triggers a reprocess of
// the current result (gated below by reprocess_current_result).
@@ -143,6 +144,7 @@ void DataProcessor::run(const std::atomic<bool>& stop_requested) {
);
publish_result_collection(result_collection, results_ring_);
publish_locator(result_collection, live_config);
consecutive_errors = 0; // made progress; reset the escalation counter
continue;
}
@@ -155,14 +157,23 @@ void DataProcessor::run(const std::atomic<bool>& stop_requested) {
throw;
}
// A single bad collection (torn ring slot, decode/processing error) must
// not kill the long-running processor: drop it and keep going. Throttle
// logging and pause briefly so a persistent error cannot busy-spin/flood.
if (error_count % 100 == 0) {
std::cerr << "data_processor: dropped collection after error (count="
<< (error_count + 1) << "): " << exc.what() << '\n';
}
// not kill the long-running processor: drop it and keep going.
++error_count;
std::this_thread::sleep_for(std::chrono::milliseconds(config_.runtime.idle_sleep_ms));
++consecutive_errors;
// Escalate a PERSISTENT failure (a deterministic config error drops every
// collection forever): log it loudly and distinctly — not buried in the
// every-100 throttle — so liveness-only supervision still surfaces it.
if (consecutive_errors % 500 == 0) {
std::cerr << "data_processor: " << consecutive_errors
<< " consecutive failures — likely a permanent configuration error: "
<< exc.what() << '\n';
} else if (error_count % 100 == 1) {
std::cerr << "data_processor: dropped collection after error (count="
<< error_count << "): " << exc.what() << '\n';
}
// Back-off (floored at 1ms even if idle_sleep_ms==0) so a persistent error
// cannot busy-spin a core or flood the log.
std::this_thread::sleep_for(std::chrono::milliseconds(std::max<int>(1, config_.runtime.idle_sleep_ms)));
}
}
}
@@ -221,6 +232,14 @@ auto DataProcessor::build_locator_filter(const ProcessingLiveConfig& live_config
live_config.processor_mode.empty() ? default_processor_mode_ : live_config.processor_mode;
radar::locator::FilterParams filter{};
// Clip broadcast objects to the same visible X/Z window the desktop plot uses,
// so the socket emits only the objects the operator actually sees.
filter.visible_bounds = radar::locator::VisibleBounds{
.x_min = live_config.gpr_visible_x_min_m,
.x_max = live_config.gpr_visible_x_max_m,
.z_min = live_config.gpr_visible_z_min_m,
.z_max = live_config.gpr_visible_z_max_m,
};
if (requested_mode == "legacy_gpr") {
filter.min_score = live_config.legacy_gpr_min_visible_pair_count;
// The GUI deliberately disables the "draw top N" capping for legacy
@@ -348,6 +348,19 @@ void apply_legacy_gpr_algorithm_alias(ProcessingLiveConfig& config, const std::s
}
config.gpr_min_visible_score = static_cast<float>(found->get<double>());
}
for (const auto& [key, target] : {
std::pair{"gpr_visible_x_min_m", &config.gpr_visible_x_min_m},
std::pair{"gpr_visible_x_max_m", &config.gpr_visible_x_max_m},
std::pair{"gpr_visible_z_min_m", &config.gpr_visible_z_min_m},
std::pair{"gpr_visible_z_max_m", &config.gpr_visible_z_max_m},
}) {
if (const auto found = root.find(key); found != root.end()) {
if (!found->is_number()) {
throw std::runtime_error(std::string("processing.") + key + " must be number");
}
*target = static_cast<float>(found->get<double>());
}
}
if (const auto found = root.find("legacy_gpr_min_visible_pair_count"); found != root.end()) {
if (!found->is_number()) {
throw std::runtime_error("processing.legacy_gpr_min_visible_pair_count must be number");