You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
9.4 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "config.h"
#include "json_utils.h"
#include <cstdio>
#include <iostream>
#include <fstream>
#include <sstream>
// ==================== 全局配置实例 ====================
AppConfig cfg;
// 解析 "HH:MM[:SS]" -> 时/分/秒;非法返回 false
static bool parse_clean_time(const std::string& s, int& h, int& m, int& sec)
{
int a = -1, b = -1, c = -1;
int n = std::sscanf(s.c_str(), "%d:%d:%d", &a, &b, &c);
if (n == 2) { h = a; m = b; sec = 0; }
else if (n == 3) { h = a; m = b; sec = c; }
else return false;
return h >= 0 && h <= 23 && m >= 0 && m <= 59 && sec >= 0 && sec <= 59;
}
// ==================== 配置加载(JSON + // 注释行,按分组嵌套解析) ====================
void load_config(const std::string& path)
{
std::ifstream fin(path);
if (!fin.is_open())
{
std::cerr << "[WARN] 未找到配置文件: " << path << std::endl;
exit(-1);
}
// 1. 剔除行首(忽略空白)以 // 开头的注释行,其余拼接为 JSON 文本
std::ostringstream json_oss;
std::string line;
while (std::getline(fin, line))
{
size_t b = line.find_first_not_of(" \t\r\n");
if (b != std::string::npos && line.compare(b, 2, "//") == 0)
continue; // 整行注释
json_oss << line << "\n";
}
fin.close();
const std::string text = json_oss.str();
std::string s; double d; bool bv;
std::vector<std::pair<double, double>> poly;
// ---------- radar: 雷达连接与雷达内置滤波 ----------
if (json_get_string(text, "radar", "ip", s)) cfg.radar.ip = s;
if (json_get_number(text, "radar", "port", d)) cfg.radar.port = (uint16_t)d;
if (json_get_number(text, "radar", "hz", d)) cfg.radar.hz = d;
if (json_get_number(text, "radar", "tail_filter", d)) cfg.radar.tail_filter = (int)d;
if (json_get_number(text, "radar", "front_filter", d)) cfg.radar.front_filter = (int)d;
if (json_get_number(text, "radar", "far_hr_filter", d)) cfg.radar.far_hr_filter = (int)d;
if (json_get_bool(text, "radar", "near_hr_filter", bv)) cfg.radar.near_hr_filter = bv;
// ---------- scan: 扫描采集与走行 ----------
if (json_get_number(text, "scan", "collect_duration_s", d)) cfg.scan.collect_duration_s = (int)d;
if (json_get_number(text, "scan", "z_speed", d)) cfg.scan.z_speed = d;
if (json_get_string(text, "scan", "z_speed_type", s))
{
if (s == "configuration" || s == "uniformSpeed") cfg.scan.z_speed_type = s;
else cfg.scan.z_speed_type = "uniformSpeed";
}
// ---------- detect: 截面分析 ----------
if (json_get_number(text, "detect", "z_range_mm", d)) cfg.detect.z_range_mm = d;
if (json_get_number(text, "detect", "y_range_mm", d)) cfg.detect.y_range_mm = d;
if (json_get_number(text, "detect", "rect_width_px", d)) cfg.detect.rect_width_px = (int)d;
if (json_get_number(text, "detect", "rect_length_ratio", d)) cfg.detect.rect_length_ratio = d;
// ---------- count: 分层计数 ----------
if (json_get_number(text, "count", "floor_height", d)) cfg.count.floor_height = d;
if (json_get_number(text, "count", "base_tolerance", d))
{
cfg.count.base_tolerance = d;
if (cfg.count.base_tolerance < 0) cfg.count.base_tolerance = 0;
}
if (json_get_number(text, "count", "per_level_tolerance", d))
{
cfg.count.per_level_tolerance = d;
if (cfg.count.per_level_tolerance < 0) cfg.count.per_level_tolerance = 0;
}
if (json_get_number(text, "count", "point_dilate", d))
{
cfg.count.point_dilate = (int)d;
if (cfg.count.point_dilate < 1) cfg.count.point_dilate = 1;
if (cfg.count.point_dilate > 64) cfg.count.point_dilate = 64;
}
if (json_get_string(text, "count", "z_interpolate_mode", s))
{
if (s == "CopyTranslation" || s == "AngleBucketInterpolation") cfg.count.z_interpolate_mode = s;
else cfg.count.z_interpolate_mode = "none";
}
// ---------- filter: 多边形过滤 ----------
poly.clear();
if (json_get_point_array(text, "filter", "polygon", poly) >= 3)
{
cfg.filter.polygon = poly;
cfg.filter.poly_n = (int)poly.size();
}
// ---------- filter.tail_cut: 图片级尾部减除(旧方案) ----------
// 三级取值:filter 组 -> tail_cut 子对象 -> 子对象内字段
{
std::string o = json_get_raw(text, "filter", "tail_cut");
if (!o.empty())
{
if (json_get_bool(o, "enable", bv)) cfg.filter.tail_cut.enable = bv;
if (json_get_number(o, "max_tail_length", d)) { cfg.filter.tail_cut.max_tail_length = (int)d; if (cfg.filter.tail_cut.max_tail_length < 0) cfg.filter.tail_cut.max_tail_length = 0; }
if (json_get_number(o, "y_delta", d)) { cfg.filter.tail_cut.y_delta = d; if (cfg.filter.tail_cut.y_delta < 0) cfg.filter.tail_cut.y_delta = 0; }
if (json_get_number(o, "min_run_length", d)) { cfg.filter.tail_cut.min_run_length = (int)d; if (cfg.filter.tail_cut.min_run_length < 1) cfg.filter.tail_cut.min_run_length = 1; }
if (json_get_number(o, "core_min_len", d)) { cfg.filter.tail_cut.core_min_len = (int)d; if (cfg.filter.tail_cut.core_min_len < 0) cfg.filter.tail_cut.core_min_len = 0; }
if (json_get_number(o, "support_rows", d)) { cfg.filter.tail_cut.support_rows = (int)d; if (cfg.filter.tail_cut.support_rows < 0) cfg.filter.tail_cut.support_rows = 0; if (cfg.filter.tail_cut.support_rows > 4) cfg.filter.tail_cut.support_rows = 4; }
}
}
// ---------- filter.sparse_cut: 点云级稀疏拖影过滤(新方案) ----------
{
std::string o = json_get_raw(text, "filter", "sparse_cut");
if (!o.empty())
{
if (json_get_bool(o, "enable", bv)) cfg.filter.sparse_cut.enable = bv;
if (json_get_number(o, "x_radius", d)) { cfg.filter.sparse_cut.x_radius = d; if (cfg.filter.sparse_cut.x_radius < 0) cfg.filter.sparse_cut.x_radius = 0; }
if (json_get_number(o, "circle_min", d)) { cfg.filter.sparse_cut.circle_min = (int)d; if (cfg.filter.sparse_cut.circle_min < 1) cfg.filter.sparse_cut.circle_min = 1; }
if (json_get_number(o, "run_min", d)) { cfg.filter.sparse_cut.run_min = (int)d; if (cfg.filter.sparse_cut.run_min < 1) cfg.filter.sparse_cut.run_min = 1; }
}
}
// ---------- server: 运行模式 ----------
if (json_get_string(text, "server", "mode", s)) cfg.server.mode = s;
if (json_get_number(text, "server", "port", d)) cfg.server.port = (uint16_t)d;
// ---------- log: 日志 ----------
if (json_get_bool(text, "log", "enable", bv)) cfg.log.enable = bv;
if (json_get_number(text, "log", "retain_days", d))
{
cfg.log.retain_days = (int)d;
if (cfg.log.retain_days < 1) cfg.log.retain_days = 1;
}
if (json_get_string(text, "log", "clean_time", s))
{
int h = -1, m = -1, sec = -1;
if (parse_clean_time(s, h, m, sec))
{
cfg.log.clean_hour = h;
cfg.log.clean_minute = m;
cfg.log.clean_sec = sec;
}
else
{
std::cout << "[WARN] log.clean_time 格式应为 \"HH:MM:SS\",已忽略: " << s
<< " (仍用 " << cfg.log.clean_hour << ":"
<< (cfg.log.clean_minute < 10 ? "0" : "") << cfg.log.clean_minute << ")"
<< std::endl;
}
}
// ==================== 打印配置摘要 ====================
std::cout << "========== 配置已加载 ==========" << std::endl;
std::cout << "雷达: " << cfg.radar.ip << ":" << cfg.radar.port
<< " 帧率: " << cfg.radar.hz << "Hz"
<< " 拖尾滤波: " << cfg.radar.tail_filter
<< " 前冲滤波: " << cfg.radar.front_filter << std::endl;
std::cout << "扫描默认时长: " << cfg.scan.collect_duration_s << "s"
<< " Z速度模式: " << cfg.scan.z_speed_type
<< " Z速度: " << cfg.scan.z_speed << "cm/s(0=时间)"
<< " 日志保留: " << cfg.log.retain_days << "天"
<< " 每日清理: " << (cfg.log.clean_hour < 10 ? "0" : "") << cfg.log.clean_hour << ":"
<< (cfg.log.clean_minute < 10 ? "0" : "") << cfg.log.clean_minute << ":"
<< (cfg.log.clean_sec < 10 ? "0" : "") << cfg.log.clean_sec << std::endl;
std::cout << "运行模式: " << cfg.server.mode
<< (cfg.server.mode == "tcp" || cfg.server.mode == "http" ? " (端口 " + std::to_string(cfg.server.port) + ")" : "") << std::endl;
std::cout << "分层冗余: 基准" << cfg.count.base_tolerance
<< " + 每层" << cfg.count.per_level_tolerance
<< " 膨胀: " << cfg.count.point_dilate
<< " 插值模式: " << cfg.count.z_interpolate_mode << std::endl;
std::cout << "过滤多边形(" << cfg.filter.poly_n << "点):";
for (const auto& p : cfg.filter.polygon)
std::cout << " (" << p.first << "," << p.second << ")";
std::cout << std::endl;
std::cout << "拖影过滤: SparseCut=" << (cfg.filter.sparse_cut.enable ? "开" : "关")
<< "(X±" << cfg.filter.sparse_cut.x_radius << "mm,同圈>=" << cfg.filter.sparse_cut.circle_min
<< ",跨圈>=" << cfg.filter.sparse_cut.run_min << ")"
<< " TailCut=" << (cfg.filter.tail_cut.enable ? "开" : "关") << std::endl;
std::cout << "================================" << std::endl;
}