GrabBag/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp
2025-12-27 09:34:02 +08:00

427 lines
19 KiB
C++

#include "VrWheelMeasureConfig.h"
#include "IVrWheelMeasureConfig.h"
#include <algorithm>
#include <sstream>
#include "VrLog.h"
#include <QFile>
#include <QTextStream>
#include <QString>
#include <QTextCodec>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
VrWheelMeasureConfig::VrWheelMeasureConfig()
: m_notify(nullptr)
{
}
VrWheelMeasureConfig::~VrWheelMeasureConfig()
{
}
// 静态工厂方法
bool IVrWheelMeasureConfig::CreateInstance(IVrWheelMeasureConfig** ppVrConfig)
{
if (!ppVrConfig) {
return false;
}
*ppVrConfig = new VrWheelMeasureConfig();
return true;
}
WheelMeasureConfigResult VrWheelMeasureConfig::LoadConfig(const std::string& filePath)
{
WheelMeasureConfigResult result;
// 使用QString处理可能包含中文的路径
QString qFilePath = QString::fromStdString(filePath);
QFile file(qFilePath);
// 检查文件是否存在并可读
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_DEBUG("Failed to open file: %s\n", filePath.c_str());
return result;
}
// 使用QXmlStreamReader解析XML内容
QXmlStreamReader xml(&file);
// 读取到根元素
if (xml.readNextStartElement()) {
if (xml.name() != "WheelMeasureConfig") {
xml.raiseError(QObject::tr("Not a WheelMeasureConfig file"));
}
} else {
xml.raiseError(QObject::tr("Failed to read root element"));
}
// 解析XML内容
while (!xml.atEnd() && !xml.hasError()) {
xml.readNext();
// 解析相机配置
if (xml.isStartElement() && xml.name() == "Cameras") {
while (xml.readNextStartElement()) {
if (xml.name() == "Camera") {
WheelCameraParam camera;
camera.cameraIndex = xml.attributes().value("index").toInt();
camera.name = xml.attributes().value("name").toString().toStdString();
camera.cameraIP = xml.attributes().value("ip").toString().toStdString();
camera.enabled = xml.attributes().value("enabled").toInt() != 0;
result.cameras.push_back(camera);
xml.skipCurrentElement();
}
}
}
// 解析相机调平参数
else if (xml.isStartElement() && xml.name() == "PlaneCalibParams") {
while (xml.readNextStartElement()) {
if (xml.name() == "CameraCalib") {
WheelCameraPlaneCalibParam calibParam;
calibParam.cameraIndex = xml.attributes().value("index").toInt();
calibParam.cameraName = xml.attributes().value("name").toString().toStdString();
calibParam.planeHeight = xml.attributes().value("planeHeight").toDouble();
calibParam.isCalibrated = xml.attributes().value("isCalibrated").toInt() != 0;
// 读取planeCalib矩阵
QString planeCalibStr = xml.attributes().value("planeCalib").toString();
QStringList planeCalibList = planeCalibStr.split(",");
for (int i = 0; i < 9 && i < planeCalibList.size(); ++i) {
calibParam.planeCalib[i] = planeCalibList[i].toDouble();
}
// 读取invRMatrix矩阵
QString invRMatrixStr = xml.attributes().value("invRMatrix").toString();
QStringList invRMatrixList = invRMatrixStr.split(",");
for (int i = 0; i < 9 && i < invRMatrixList.size(); ++i) {
calibParam.invRMatrix[i] = invRMatrixList[i].toDouble();
}
result.planeCalibParams.push_back(calibParam);
xml.skipCurrentElement();
}
}
}
// 解析算法参数
else if (xml.isStartElement() && xml.name() == "AlgorithmParams") {
while (xml.readNextStartElement()) {
// 角点参数
if (xml.name() == "CornerParam") {
result.algorithmParams.cornerParam.minEndingGap =
xml.attributes().value("minEndingGap").toDouble();
result.algorithmParams.cornerParam.minEndingGap_z =
xml.attributes().value("minEndingGap_z").toDouble();
result.algorithmParams.cornerParam.scale =
xml.attributes().value("scale").toDouble();
result.algorithmParams.cornerParam.cornerTh =
xml.attributes().value("cornerTh").toDouble();
result.algorithmParams.cornerParam.jumpCornerTh_1 =
xml.attributes().value("jumpCornerTh_1").toDouble();
result.algorithmParams.cornerParam.jumpCornerTh_2 =
xml.attributes().value("jumpCornerTh_2").toDouble();
// 设置默认值
if (result.algorithmParams.cornerParam.minEndingGap == 0.0) {
result.algorithmParams.cornerParam.minEndingGap = 3.0;
}
if (result.algorithmParams.cornerParam.minEndingGap_z == 0.0) {
result.algorithmParams.cornerParam.minEndingGap_z = 5.0;
}
if (result.algorithmParams.cornerParam.scale == 0.0) {
result.algorithmParams.cornerParam.scale = 10.0;
}
if (result.algorithmParams.cornerParam.cornerTh == 0.0) {
result.algorithmParams.cornerParam.cornerTh = 130.0;
}
if (result.algorithmParams.cornerParam.jumpCornerTh_1 == 0.0) {
result.algorithmParams.cornerParam.jumpCornerTh_1 = 5.0;
}
if (result.algorithmParams.cornerParam.jumpCornerTh_2 == 0.0) {
result.algorithmParams.cornerParam.jumpCornerTh_2 = 2.0;
}
xml.skipCurrentElement();
}
// 线段参数
else if (xml.name() == "LineSegParam") {
result.algorithmParams.lineSegParam.segGapTh_y =
xml.attributes().value("segGapTh_y").toDouble();
result.algorithmParams.lineSegParam.segGapTh_z =
xml.attributes().value("segGapTh_z").toDouble();
result.algorithmParams.lineSegParam.maxDist =
xml.attributes().value("maxDist").toDouble();
// 设置默认值
if (result.algorithmParams.lineSegParam.segGapTh_y == 0.0) {
result.algorithmParams.lineSegParam.segGapTh_y = 5.0;
}
if (result.algorithmParams.lineSegParam.segGapTh_z == 0.0) {
result.algorithmParams.lineSegParam.segGapTh_z = 10.0;
}
if (result.algorithmParams.lineSegParam.maxDist == 0.0) {
result.algorithmParams.lineSegParam.maxDist = 50.0;
}
xml.skipCurrentElement();
}
// 离群点过滤参数
else if (xml.name() == "OutlierFilterParam") {
result.algorithmParams.filterParam.continuityTh =
xml.attributes().value("continuityTh").toDouble();
result.algorithmParams.filterParam.outlierTh =
xml.attributes().value("outlierTh").toDouble();
// 设置默认值
if (result.algorithmParams.filterParam.continuityTh == 0.0) {
result.algorithmParams.filterParam.continuityTh = 5.0;
}
if (result.algorithmParams.filterParam.outlierTh == 0.0) {
result.algorithmParams.filterParam.outlierTh = 3.0;
}
xml.skipCurrentElement();
}
// 树生长参数
else if (xml.name() == "TreeGrowParam") {
result.algorithmParams.growParam.yDeviation_max =
xml.attributes().value("yDeviation_max").toDouble();
result.algorithmParams.growParam.zDeviation_max =
xml.attributes().value("zDeviation_max").toDouble();
result.algorithmParams.growParam.maxLineSkipNum =
xml.attributes().value("maxLineSkipNum").toInt();
result.algorithmParams.growParam.maxSkipDistance =
xml.attributes().value("maxSkipDistance").toDouble();
result.algorithmParams.growParam.minLTypeTreeLen =
xml.attributes().value("minLTypeTreeLen").toDouble();
result.algorithmParams.growParam.minVTypeTreeLen =
xml.attributes().value("minVTypeTreeLen").toDouble();
// 设置默认值
if (result.algorithmParams.growParam.yDeviation_max == 0.0) {
result.algorithmParams.growParam.yDeviation_max = 20.0;
}
if (result.algorithmParams.growParam.zDeviation_max == 0.0) {
result.algorithmParams.growParam.zDeviation_max = 30.0;
}
if (result.algorithmParams.growParam.maxLineSkipNum == 0) {
result.algorithmParams.growParam.maxLineSkipNum = 5;
}
if (result.algorithmParams.growParam.minLTypeTreeLen == 0.0) {
result.algorithmParams.growParam.minLTypeTreeLen = 10.0;
}
if (result.algorithmParams.growParam.minVTypeTreeLen == 0.0) {
result.algorithmParams.growParam.minVTypeTreeLen = 10.0;
}
xml.skipCurrentElement();
}
else {
xml.skipCurrentElement();
}
}
}
// 解析调试参数
else if (xml.isStartElement() && xml.name() == "DebugParam") {
result.debugParam.enableDebug = xml.attributes().value("enableDebug").toInt();
result.debugParam.saveDebugImage = xml.attributes().value("saveDebugImage").toInt();
result.debugParam.printDetailLog = xml.attributes().value("printDetailLog").toInt();
result.debugParam.debugOutputPath = xml.attributes().value("debugOutputPath").toString().toStdString();
xml.skipCurrentElement();
}
// 解析服务端配置
else if (xml.isStartElement() && xml.name() == "LocalServerConfig") {
while (xml.readNextStartElement()) {
if (xml.name() == "ServerPort") {
result.serverPort = xml.attributes().value("port").toInt();
xml.skipCurrentElement();
} else if (xml.name() == "TcpPort") {
result.tcpPort = xml.attributes().value("port").toInt();
if (result.tcpPort == 0) {
result.tcpPort = 5800; // 默认值
}
xml.skipCurrentElement();
} else {
xml.skipCurrentElement();
}
}
}
// 解析服务器列表
else if (xml.isStartElement() && xml.name() == "Servers") {
while (xml.readNextStartElement()) {
if (xml.name() == "Server") {
WheelServerInfo server;
server.name = xml.attributes().value("name").toString().toStdString();
server.ip = xml.attributes().value("ip").toString().toStdString();
server.port = xml.attributes().value("port").toInt();
if (server.port == 0) {
server.port = 5800; // 默认端口
}
result.servers.push_back(server);
xml.skipCurrentElement();
} else {
xml.skipCurrentElement();
}
}
}
}
file.close();
// 检查解析错误
if (xml.hasError()) {
LOG_ERROR("XML parsing error: %s\n", xml.errorString().toStdString().c_str());
return WheelMeasureConfigResult(); // 返回空结果
}
return result;
}
bool VrWheelMeasureConfig::SaveConfig(const std::string& filePath, WheelMeasureConfigResult& configResult)
{
// 使用QString处理可能包含中文的路径
QString qFilePath = QString::fromStdString(filePath);
QFile file(qFilePath);
// 打开文件进行写入
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
LOG_DEBUG("Failed to open file for writing: %s\n", filePath.c_str());
return false;
}
// 使用QXmlStreamWriter写入XML内容
QXmlStreamWriter xml(&file);
xml.setAutoFormatting(true);
xml.setCodec("UTF-8");
xml.writeStartDocument();
xml.writeStartElement("WheelMeasureConfig");
// 保存相机配置
xml.writeStartElement("Cameras");
for (const auto& camera : configResult.cameras) {
xml.writeStartElement("Camera");
xml.writeAttribute("index", QString::number(camera.cameraIndex));
xml.writeAttribute("name", QString::fromStdString(camera.name));
xml.writeAttribute("ip", QString::fromStdString(camera.cameraIP));
xml.writeAttribute("enabled", QString::number(camera.enabled ? 1 : 0));
xml.writeEndElement(); // Camera
}
xml.writeEndElement(); // Cameras
// 保存相机调平参数
xml.writeStartElement("PlaneCalibParams");
for (const auto& calibParam : configResult.planeCalibParams) {
xml.writeStartElement("CameraCalib");
xml.writeAttribute("index", QString::number(calibParam.cameraIndex));
xml.writeAttribute("name", QString::fromStdString(calibParam.cameraName));
xml.writeAttribute("planeHeight", QString::number(calibParam.planeHeight, 'f', 6));
xml.writeAttribute("isCalibrated", QString::number(calibParam.isCalibrated ? 1 : 0));
// 保存planeCalib矩阵
QStringList planeCalibList;
for (int i = 0; i < 9; ++i) {
planeCalibList.append(QString::number(calibParam.planeCalib[i], 'f', 8));
}
xml.writeAttribute("planeCalib", planeCalibList.join(","));
// 保存invRMatrix矩阵
QStringList invRMatrixList;
for (int i = 0; i < 9; ++i) {
invRMatrixList.append(QString::number(calibParam.invRMatrix[i], 'f', 8));
}
xml.writeAttribute("invRMatrix", invRMatrixList.join(","));
xml.writeEndElement(); // CameraCalib
}
xml.writeEndElement(); // PlaneCalibParams
// 保存算法参数
xml.writeStartElement("AlgorithmParams");
// 角点参数
xml.writeStartElement("CornerParam");
xml.writeAttribute("minEndingGap", QString::number(configResult.algorithmParams.cornerParam.minEndingGap));
xml.writeAttribute("minEndingGap_z", QString::number(configResult.algorithmParams.cornerParam.minEndingGap_z));
xml.writeAttribute("scale", QString::number(configResult.algorithmParams.cornerParam.scale));
xml.writeAttribute("cornerTh", QString::number(configResult.algorithmParams.cornerParam.cornerTh));
xml.writeAttribute("jumpCornerTh_1", QString::number(configResult.algorithmParams.cornerParam.jumpCornerTh_1));
xml.writeAttribute("jumpCornerTh_2", QString::number(configResult.algorithmParams.cornerParam.jumpCornerTh_2));
xml.writeEndElement(); // CornerParam
// 线段参数
xml.writeStartElement("LineSegParam");
xml.writeAttribute("segGapTh_y", QString::number(configResult.algorithmParams.lineSegParam.segGapTh_y));
xml.writeAttribute("segGapTh_z", QString::number(configResult.algorithmParams.lineSegParam.segGapTh_z));
xml.writeAttribute("maxDist", QString::number(configResult.algorithmParams.lineSegParam.maxDist));
xml.writeEndElement(); // LineSegParam
// 离群点过滤参数
xml.writeStartElement("OutlierFilterParam");
xml.writeAttribute("continuityTh", QString::number(configResult.algorithmParams.filterParam.continuityTh));
xml.writeAttribute("outlierTh", QString::number(configResult.algorithmParams.filterParam.outlierTh));
xml.writeEndElement(); // OutlierFilterParam
// 树生长参数
xml.writeStartElement("TreeGrowParam");
xml.writeAttribute("yDeviation_max", QString::number(configResult.algorithmParams.growParam.yDeviation_max));
xml.writeAttribute("zDeviation_max", QString::number(configResult.algorithmParams.growParam.zDeviation_max));
xml.writeAttribute("maxLineSkipNum", QString::number(configResult.algorithmParams.growParam.maxLineSkipNum));
xml.writeAttribute("maxSkipDistance", QString::number(configResult.algorithmParams.growParam.maxSkipDistance));
xml.writeAttribute("minLTypeTreeLen", QString::number(configResult.algorithmParams.growParam.minLTypeTreeLen));
xml.writeAttribute("minVTypeTreeLen", QString::number(configResult.algorithmParams.growParam.minVTypeTreeLen));
xml.writeEndElement(); // TreeGrowParam
xml.writeEndElement(); // AlgorithmParams
// 保存调试参数
xml.writeStartElement("DebugParam");
xml.writeAttribute("enableDebug", QString::number(configResult.debugParam.enableDebug));
xml.writeAttribute("saveDebugImage", QString::number(configResult.debugParam.saveDebugImage));
xml.writeAttribute("printDetailLog", QString::number(configResult.debugParam.printDetailLog));
xml.writeAttribute("debugOutputPath", QString::fromStdString(configResult.debugParam.debugOutputPath));
xml.writeEndElement(); // DebugParam
// 保存服务端配置
xml.writeStartElement("LocalServerConfig");
xml.writeStartElement("ServerPort");
xml.writeAttribute("port", QString::number(configResult.serverPort));
xml.writeEndElement(); // ServerPort
xml.writeStartElement("TcpPort");
xml.writeAttribute("port", QString::number(configResult.tcpPort));
xml.writeEndElement(); // TcpPort
xml.writeEndElement(); // LocalServerConfig
// 保存服务器列表
xml.writeStartElement("Servers");
for (const auto& server : configResult.servers) {
xml.writeStartElement("Server");
xml.writeAttribute("name", QString::fromStdString(server.name));
xml.writeAttribute("ip", QString::fromStdString(server.ip));
xml.writeAttribute("port", QString::number(server.port));
xml.writeEndElement(); // Server
}
xml.writeEndElement(); // Servers
xml.writeEndElement(); // WheelMeasureConfig
xml.writeEndDocument();
file.close();
// 通知配置改变
if (m_notify) {
m_notify->OnConfigChanged(configResult);
}
return true;
}
void VrWheelMeasureConfig::SetConfigChangeNotify(IVrWheelMeasureConfigChangeNotify* notify)
{
m_notify = notify;
}