#include "VrConfig.h" #include #include #include #include "VrLog.h" #include "ConfigXmlUtils.h" using namespace tinyxml2; CVrConfig::CVrConfig() : m_pNotify(nullptr) { } CVrConfig::~CVrConfig() { // 析构函数 } int CVrConfig::LoadConfig(const std::string& filePath, ConfigResult& configResult) { // 使用tinyxml2库加载XML文件 XMLDocument doc; XMLError err = doc.LoadFile(filePath.c_str()); if (err != XML_SUCCESS) { LOG_ERR("open config file failed: %s\n", filePath.c_str()); return LOAD_CONFIG_FILE_NOT_FOUND; } // 获取根元素 XMLElement* root = doc.RootElement(); if (!root || std::string(root->Name()) != "HoleDetectionConfig") { std::cerr << "config file format error: root element is not HoleDetectionConfig" << std::endl; return LOAD_CONFIG_INVALID_FORMAT; } // 解析摄像头列表 ConfigXmlUtils::LoadCameraList(root, configResult.cameraList); // 解析设备列表 XMLElement* devicesElement = root->FirstChildElement("Devices"); if (devicesElement) { XMLElement* deviceElement = devicesElement->FirstChildElement("Device"); while (deviceElement) { DeviceInfo device; if (deviceElement->Attribute("name")) device.name = deviceElement->Attribute("name"); if (deviceElement->Attribute("ip")) device.ip = deviceElement->Attribute("ip"); configResult.deviceList.push_back(device); deviceElement = deviceElement->NextSiblingElement("Device"); } } // 解析算法参数 XMLElement* algoParamsElement = root->FirstChildElement("AlgorithmParams"); if (algoParamsElement) { // 解析孔洞检测参数(14个) XMLElement* detectionParamElement = algoParamsElement->FirstChildElement("DetectionParam"); if (detectionParamElement) { if (detectionParamElement->Attribute("neighborCount")) configResult.algorithmParams.detectionParam.neighborCount = detectionParamElement->IntAttribute("neighborCount"); if (detectionParamElement->Attribute("angleThresholdPos")) configResult.algorithmParams.detectionParam.angleThresholdPos = detectionParamElement->DoubleAttribute("angleThresholdPos"); if (detectionParamElement->Attribute("angleThresholdNeg")) configResult.algorithmParams.detectionParam.angleThresholdNeg = detectionParamElement->DoubleAttribute("angleThresholdNeg"); if (detectionParamElement->Attribute("minPitDepth")) configResult.algorithmParams.detectionParam.minPitDepth = detectionParamElement->DoubleAttribute("minPitDepth"); if (detectionParamElement->Attribute("minRadius")) configResult.algorithmParams.detectionParam.minRadius = detectionParamElement->DoubleAttribute("minRadius"); if (detectionParamElement->Attribute("maxRadius")) configResult.algorithmParams.detectionParam.maxRadius = detectionParamElement->DoubleAttribute("maxRadius"); if (detectionParamElement->Attribute("expansionSize1")) configResult.algorithmParams.detectionParam.expansionSize1 = detectionParamElement->IntAttribute("expansionSize1"); if (detectionParamElement->Attribute("expansionSize2")) configResult.algorithmParams.detectionParam.expansionSize2 = detectionParamElement->IntAttribute("expansionSize2"); if (detectionParamElement->Attribute("minVTransitionPoints")) configResult.algorithmParams.detectionParam.minVTransitionPoints = detectionParamElement->IntAttribute("minVTransitionPoints"); } // 解析孔洞过滤参数 XMLElement* filterParamElement = algoParamsElement->FirstChildElement("FilterParam"); if (filterParamElement) { if (filterParamElement->Attribute("maxEccentricity")) configResult.algorithmParams.filterParam.maxEccentricity = filterParamElement->DoubleAttribute("maxEccentricity"); if (filterParamElement->Attribute("minAngularCoverage")) configResult.algorithmParams.filterParam.minAngularCoverage = filterParamElement->DoubleAttribute("minAngularCoverage"); if (filterParamElement->Attribute("maxRadiusFitRatio")) configResult.algorithmParams.filterParam.maxRadiusFitRatio = filterParamElement->DoubleAttribute("maxRadiusFitRatio"); if (filterParamElement->Attribute("minQualityScore")) configResult.algorithmParams.filterParam.minQualityScore = filterParamElement->DoubleAttribute("minQualityScore"); if (filterParamElement->Attribute("maxPlaneResidual")) configResult.algorithmParams.filterParam.maxPlaneResidual = filterParamElement->DoubleAttribute("maxPlaneResidual"); if (filterParamElement->Attribute("maxAngularGap")) configResult.algorithmParams.filterParam.maxAngularGap = filterParamElement->DoubleAttribute("maxAngularGap"); if (filterParamElement->Attribute("minInlierRatio")) configResult.algorithmParams.filterParam.minInlierRatio = filterParamElement->DoubleAttribute("minInlierRatio"); } // 解析排序模式 XMLElement* sortModeElement = algoParamsElement->FirstChildElement("SortMode"); if (sortModeElement) { if (sortModeElement->Attribute("value")) configResult.algorithmParams.sortMode = sortModeElement->IntAttribute("value"); } // 解析多相机平面校准参数 ConfigXmlUtils::LoadPlaneCalibParams(algoParamsElement, configResult.algorithmParams.planeCalibParam); } // 解析调试参数 ConfigXmlUtils::LoadDebugParam(root, configResult.debugParam); // 解析串口配置 ConfigXmlUtils::LoadSerialConfig(root, configResult.serialConfig); // 解析手眼标定矩阵列表(支持多相机) ConfigXmlUtils::LoadHandEyeCalibMatrixs(root, configResult.handEyeCalibMatrixList); // 解析TCP服务端配置 XMLElement* tcpServerConfigElement = root->FirstChildElement("TcpServerConfig"); if (tcpServerConfigElement) { // 解析TCP协议端口 if (tcpServerConfigElement->Attribute("tcpServerPort")) configResult.plcRobotServerConfig.tcpServerPort = tcpServerConfigElement->IntAttribute("tcpServerPort"); else configResult.plcRobotServerConfig.tcpServerPort = 7800; // 默认7800 // 解析姿态输出顺序配置 if (tcpServerConfigElement->Attribute("poseOutputOrder")) configResult.plcRobotServerConfig.poseOutputOrder = tcpServerConfigElement->IntAttribute("poseOutputOrder"); else configResult.plcRobotServerConfig.poseOutputOrder = POSE_ORDER_RPY; // 默认RPY // 解析方向向量反向配置 if (tcpServerConfigElement->Attribute("dirVectorInvert")) configResult.plcRobotServerConfig.dirVectorInvert = tcpServerConfigElement->IntAttribute("dirVectorInvert"); else configResult.plcRobotServerConfig.dirVectorInvert = DIR_INVERT_YZ; // 默认YZ反向 } return LOAD_CONFIG_SUCCESS; } bool CVrConfig::SaveConfig(const std::string& filePath, ConfigResult& configResult) { // 创建XML文档 XMLDocument doc; // 添加声明 XMLDeclaration* declaration = doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\""); doc.InsertFirstChild(declaration); // 创建根元素 XMLElement* root = doc.NewElement("HoleDetectionConfig"); doc.InsertEndChild(root); // 添加摄像头列表 ConfigXmlUtils::SaveCameraList(doc, root, configResult.cameraList); // 添加设备列表 XMLElement* devicesElement = doc.NewElement("Devices"); root->InsertEndChild(devicesElement); for (const auto& device : configResult.deviceList) { XMLElement* deviceElement = doc.NewElement("Device"); deviceElement->SetAttribute("name", device.name.c_str()); deviceElement->SetAttribute("ip", device.ip.c_str()); devicesElement->InsertEndChild(deviceElement); } // 添加算法参数 XMLElement* algoParamsElement = doc.NewElement("AlgorithmParams"); root->InsertEndChild(algoParamsElement); // 添加孔洞检测参数 XMLElement* detectionParamElement = doc.NewElement("DetectionParam"); detectionParamElement->SetAttribute("neighborCount", configResult.algorithmParams.detectionParam.neighborCount); detectionParamElement->SetAttribute("angleThresholdPos", configResult.algorithmParams.detectionParam.angleThresholdPos); detectionParamElement->SetAttribute("angleThresholdNeg", configResult.algorithmParams.detectionParam.angleThresholdNeg); detectionParamElement->SetAttribute("minPitDepth", configResult.algorithmParams.detectionParam.minPitDepth); detectionParamElement->SetAttribute("minRadius", configResult.algorithmParams.detectionParam.minRadius); detectionParamElement->SetAttribute("maxRadius", configResult.algorithmParams.detectionParam.maxRadius); detectionParamElement->SetAttribute("expansionSize1", configResult.algorithmParams.detectionParam.expansionSize1); detectionParamElement->SetAttribute("expansionSize2", configResult.algorithmParams.detectionParam.expansionSize2); detectionParamElement->SetAttribute("minVTransitionPoints", configResult.algorithmParams.detectionParam.minVTransitionPoints); algoParamsElement->InsertEndChild(detectionParamElement); // 添加孔洞过滤参数 XMLElement* filterParamElement = doc.NewElement("FilterParam"); filterParamElement->SetAttribute("maxEccentricity", configResult.algorithmParams.filterParam.maxEccentricity); filterParamElement->SetAttribute("minAngularCoverage", configResult.algorithmParams.filterParam.minAngularCoverage); filterParamElement->SetAttribute("maxRadiusFitRatio", configResult.algorithmParams.filterParam.maxRadiusFitRatio); filterParamElement->SetAttribute("minQualityScore", configResult.algorithmParams.filterParam.minQualityScore); filterParamElement->SetAttribute("maxPlaneResidual", configResult.algorithmParams.filterParam.maxPlaneResidual); filterParamElement->SetAttribute("maxAngularGap", configResult.algorithmParams.filterParam.maxAngularGap); filterParamElement->SetAttribute("minInlierRatio", configResult.algorithmParams.filterParam.minInlierRatio); algoParamsElement->InsertEndChild(filterParamElement); // 添加排序模式 XMLElement* sortModeElement = doc.NewElement("SortMode"); sortModeElement->SetAttribute("value", configResult.algorithmParams.sortMode); algoParamsElement->InsertEndChild(sortModeElement); // 添加多相机平面校准参数 ConfigXmlUtils::SavePlaneCalibParams(doc, algoParamsElement, configResult.algorithmParams.planeCalibParam); // 添加调试参数 ConfigXmlUtils::SaveDebugParam(doc, root, configResult.debugParam); // 添加串口配置 ConfigXmlUtils::SaveSerialConfig(doc, root, configResult.serialConfig); // 添加手眼标定矩阵列表(支持多相机) ConfigXmlUtils::SaveHandEyeCalibMatrixs(doc, root, configResult.handEyeCalibMatrixList); // 添加TCP服务端配置 XMLElement* tcpServerConfigElement = doc.NewElement("TcpServerConfig"); tcpServerConfigElement->SetAttribute("tcpServerPort", configResult.plcRobotServerConfig.tcpServerPort); // 保存姿态输出顺序配置 tcpServerConfigElement->SetAttribute("poseOutputOrder", configResult.plcRobotServerConfig.poseOutputOrder); // 保存方向向量反向配置 tcpServerConfigElement->SetAttribute("dirVectorInvert", configResult.plcRobotServerConfig.dirVectorInvert); root->InsertEndChild(tcpServerConfigElement); // 保存到文件 XMLError err = doc.SaveFile(filePath.c_str()); if (err != XML_SUCCESS) { std::cerr << "无法保存配置文件: " << filePath << std::endl; return false; } // 触发配置改变通知 if (m_pNotify) { m_pNotify->OnConfigChanged(configResult); } return true; } // 设置配置改变通知回调 void CVrConfig::SetConfigChangeNotify(IVrConfigChangeNotify* notify) { m_pNotify = notify; } /** * @brief 创建实例 * @return 实例 */ bool IVrConfig::CreateInstance(IVrConfig** ppVrConfig) { *ppVrConfig = new CVrConfig(); return *ppVrConfig != nullptr; }