#include "VrWheelMeasureConfig.h" #include "IVrWheelMeasureConfig.h" #include #include #include "VrLog.h" #include #include #include #include #include #include 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; }