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.

210 lines
10 KiB
C++

2 months ago
#include "config.h"
#include "json_utils.h"
#include <cstdio>
2 months ago
#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 + // 注释行,按分组嵌套解析) ====================
2 months ago
void load_config(const std::string& path)
{
std::ifstream fin(path);
if (!fin.is_open())
{
2 months ago
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";
}
if (json_get_string(text, "count", "layer_algorithm", s))
{
if (s == "HalfMax" || s == "KdePeak") cfg.count.layer_algorithm = s;
else cfg.count.layer_algorithm = "LevelTolerance"; // 非法值回退默认算法
}
if (json_get_number(text, "count", "kde_bandwidth", d))
{
cfg.count.kde_bandwidth = d;
if (cfg.count.kde_bandwidth < 0) cfg.count.kde_bandwidth = 0;
}
if (json_get_number(text, "count", "kde_step", d))
{
cfg.count.kde_step = d;
if (cfg.count.kde_step < 0.1) cfg.count.kde_step = 0.1; // 步长过小无意义且极慢
if (cfg.count.kde_step > 100.0) cfg.count.kde_step = 100.0;
}
// ---------- 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))
2 months ago
{
cfg.log.retain_days = (int)d;
if (cfg.log.retain_days < 1) cfg.log.retain_days = 1;
2 months ago
}
if (json_get_string(text, "log", "clean_time", s))
2 months ago
{
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;
}
2 months ago
}
// ==================== 打印配置摘要 ====================
2 months ago
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.layer_algorithm
<< " 膨胀: " << cfg.count.point_dilate
<< " 插值模式: " << cfg.count.z_interpolate_mode << std::endl;
if (cfg.count.layer_algorithm == "KdePeak")
std::cout << "KDE峰值: 带宽=" << cfg.count.kde_bandwidth
<< "(0=自动)mm 步长=" << cfg.count.kde_step << "mm" << std::endl;
std::cout << "过滤多边形(" << cfg.filter.poly_n << "点):";
for (const auto& p : cfg.filter.polygon)
2 months ago
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;
2 months ago
std::cout << "================================" << std::endl;
}