#include "config.h" #include "json_utils.h" #include #include #include #include // ==================== 全局配置实例 ==================== 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> 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; }