2026-02-02 23:24:24 +08:00

490 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "dialogalgoarg.h"
#include "ui_dialogalgoarg.h"
#include <QMessageBox>
#include <QPushButton>
#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QStandardPaths>
#include <QtCore/QFile>
#include <cstring>
#include <QSettings>
#include <QFileDialog>
#include "PathManager.h"
#include "StyledMessageBox.h"
#include "VrLog.h"
DialogAlgoarg::DialogAlgoarg(ConfigManager* configManager, QWidget *parent)
: QDialog(parent)
, ui(new Ui::DialogAlgoarg)
, m_pConfigManager(configManager)
{
try {
ui->setupUi(this);
// 隐藏标题栏
// setWindowFlags(Qt::FramelessWindowHint);
// 获取配置文件路径
m_configFilePath = PathManager::GetInstance().GetConfigFilePath();
// 检查配置文件路径是否有效
if (m_configFilePath.isEmpty()) {
StyledMessageBox::critical(this, "错误", "无法获取配置文件路径!");
return;
}
// 初始化旋转顺序下拉框
InitEulerOrderComboBox();
// 初始化姿态输出顺序下拉框
InitPoseOutputOrderComboBox();
// 初始化方向向量反向下拉框
InitDirVectorInvertComboBox();
// 从配置文件加载数据到界面
LoadConfigToUI();
} catch (const std::exception& e) {
StyledMessageBox::critical(this, "初始化错误", QString("对话框初始化失败: %1").arg(e.what()));
} catch (...) {
StyledMessageBox::critical(this, "初始化错误", "对话框初始化失败!(未知错误)");
}
}
DialogAlgoarg::~DialogAlgoarg()
{
delete ui;
}
void DialogAlgoarg::LoadConfigToUI()
{
if (!m_pConfigManager) {
StyledMessageBox::critical(this, "错误", "配置对象未初始化!");
return;
}
try {
// 从ConfigManager获取配置数据
ConfigResult configData = m_pConfigManager->GetConfigResult();
// 检查配置文件路径是否有效
if (m_configFilePath.isEmpty()) {
LOG_WARNING("Config file path is empty\n");
}
// 加载算法参数到UI
const VrAlgorithmParams& algoParams = configData.algorithmParams;
// 加载各个参数组
LoadWorkpieceHoleParamToUI(algoParams.workpieceHoleParam);
LoadLineSegParamToUI(algoParams.lineSegParam);
LoadFilterParamToUI(algoParams.filterParam);
LoadGrowParamToUI(algoParams.growParam);
// 加载网络配置PLC和机械臂服务端
LoadPlcRobotServerConfigToUI(configData.plcRobotServerConfig);
// 加载手眼标定矩阵
LoadCalibMatrixToUI();
} catch (const std::exception& e) {
LOG_ERROR("Exception in LoadConfigToUI: %s\n", e.what());
StyledMessageBox::warning(this, "警告",
QString("加载配置时发生异常: %1\n将使用默认参数显示").arg(e.what()));
// 发生异常时使用默认参数
ConfigResult configData;
const VrAlgorithmParams& algoParams = configData.algorithmParams;
LoadWorkpieceHoleParamToUI(algoParams.workpieceHoleParam);
LoadLineSegParamToUI(algoParams.lineSegParam);
LoadFilterParamToUI(algoParams.filterParam);
LoadGrowParamToUI(algoParams.growParam);
} catch (...) {
LOG_ERROR("Unknown exception in LoadConfigToUI\n");
StyledMessageBox::warning(this, "警告", "加载配置文件失败(未知错误),将使用默认参数显示");
// 发生未知异常时使用默认参数
ConfigResult configData;
const VrAlgorithmParams& algoParams = configData.algorithmParams;
LoadWorkpieceHoleParamToUI(algoParams.workpieceHoleParam);
LoadLineSegParamToUI(algoParams.lineSegParam);
LoadFilterParamToUI(algoParams.filterParam);
LoadGrowParamToUI(algoParams.growParam);
}
}
void DialogAlgoarg::LoadWorkpieceHoleParamToUI(const VrWorkpieceHoleParam& param)
{
if (!ui) return;
ui->lineEdit_workpieceType->setText(QString::number(param.workpieceType));
ui->lineEdit_holeDiameter->setText(QString::number(param.holeDiameter));
ui->lineEdit_holeDist_L->setText(QString::number(param.holeDist_L));
ui->lineEdit_holeDist_W->setText(QString::number(param.holeDist_W));
}
void DialogAlgoarg::LoadLineSegParamToUI(const VrLineSegParam& param)
{
if (!ui) return;
ui->lineEdit_distScale->setText(QString::number(param.distScale));
ui->lineEdit_segGapTh_y->setText(QString::number(param.segGapTh_y));
ui->lineEdit_segGapTh_z->setText(QString::number(param.segGapTh_z));
}
void DialogAlgoarg::LoadFilterParamToUI(const VrOutlierFilterParam& param)
{
if (!ui) return;
ui->lineEdit_continuityTh->setText(QString::number(param.continuityTh));
ui->lineEdit_outlierTh->setText(QString::number(param.outlierTh));
}
void DialogAlgoarg::LoadGrowParamToUI(const VrTreeGrowParam& param)
{
if (!ui) return;
ui->lineEdit_maxLineSkipNum->setText(QString::number(param.maxLineSkipNum));
ui->lineEdit_yDeviation_max->setText(QString::number(param.yDeviation_max));
ui->lineEdit_maxSkipDistance->setText(QString::number(param.maxSkipDistance));
ui->lineEdit_zDeviation_max->setText(QString::number(param.zDeviation_max));
ui->lineEdit_minLTypeTreeLen->setText(QString::number(param.minLTypeTreeLen));
ui->lineEdit_minVTypeTreeLen->setText(QString::number(param.minVTypeTreeLen));
}
bool DialogAlgoarg::SaveConfigFromUI()
{
if (!m_pConfigManager) {
return false;
}
try {
// 获取当前配置
SystemConfig systemConfig = m_pConfigManager->GetConfig();
VrAlgorithmParams& algoParams = systemConfig.configResult.algorithmParams;
// 保存各个参数组
if (!SaveWorkpieceHoleParamFromUI(algoParams.workpieceHoleParam)) {
StyledMessageBox::warning(this, "错误", "工件孔参数输入有误,请检查!");
return false;
}
if (!SaveLineSegParamFromUI(algoParams.lineSegParam)) {
StyledMessageBox::warning(this, "错误", "线段分割参数输入有误,请检查!");
return false;
}
if (!SaveFilterParamFromUI(algoParams.filterParam)) {
StyledMessageBox::warning(this, "错误", "滤波参数输入有误,请检查!");
return false;
}
if (!SaveGrowParamFromUI(algoParams.growParam)) {
StyledMessageBox::warning(this, "错误", "生长参数输入有误,请检查!");
return false;
}
// 保存网络配置PLC和机械臂服务端
if (!SavePlcRobotServerConfigFromUI(systemConfig.configResult.plcRobotServerConfig)) {
StyledMessageBox::warning(this, "错误", "网络配置输入有误,请检查!");
return false;
}
// 保存手眼标定矩阵到配置
if (!SaveCalibMatrixToConfig(systemConfig.configResult.handEyeCalibMatrix)) {
StyledMessageBox::warning(this, "错误", "手眼标定矩阵输入有误,请检查!");
return false;
}
// 更新并保存配置到文件
if (!m_pConfigManager->UpdateFullConfig(systemConfig)) {
return false;
}
return m_pConfigManager->SaveConfigToFile(m_configFilePath.toStdString());
} catch (const std::exception& e) {
return false;
}
}
bool DialogAlgoarg::SaveWorkpieceHoleParamFromUI(VrWorkpieceHoleParam& param)
{
bool ok = true;
param.workpieceType = ui->lineEdit_workpieceType->text().toInt(&ok);
if (!ok) return false;
param.holeDiameter = ui->lineEdit_holeDiameter->text().toDouble(&ok);
if (!ok) return false;
param.holeDist_L = ui->lineEdit_holeDist_L->text().toDouble(&ok);
if (!ok) return false;
param.holeDist_W = ui->lineEdit_holeDist_W->text().toDouble(&ok);
if (!ok) return false;
return true;
}
bool DialogAlgoarg::SaveLineSegParamFromUI(VrLineSegParam& param)
{
bool ok = true;
param.distScale = ui->lineEdit_distScale->text().toDouble(&ok);
if (!ok) return false;
param.segGapTh_y = ui->lineEdit_segGapTh_y->text().toDouble(&ok);
if (!ok) return false;
param.segGapTh_z = ui->lineEdit_segGapTh_z->text().toDouble(&ok);
if (!ok) return false;
return true;
}
bool DialogAlgoarg::SaveFilterParamFromUI(VrOutlierFilterParam& param)
{
bool ok = true;
param.continuityTh = ui->lineEdit_continuityTh->text().toDouble(&ok);
if (!ok) return false;
param.outlierTh = ui->lineEdit_outlierTh->text().toDouble(&ok);
if (!ok) return false;
return true;
}
bool DialogAlgoarg::SaveGrowParamFromUI(VrTreeGrowParam& param)
{
bool ok = true;
param.maxLineSkipNum = ui->lineEdit_maxLineSkipNum->text().toInt(&ok);
if (!ok) return false;
param.yDeviation_max = ui->lineEdit_yDeviation_max->text().toDouble(&ok);
if (!ok) return false;
param.maxSkipDistance = ui->lineEdit_maxSkipDistance->text().toDouble(&ok);
if (!ok) return false;
param.zDeviation_max = ui->lineEdit_zDeviation_max->text().toDouble(&ok);
if (!ok) return false;
param.minLTypeTreeLen = ui->lineEdit_minLTypeTreeLen->text().toDouble(&ok);
if (!ok) return false;
param.minVTypeTreeLen = ui->lineEdit_minVTypeTreeLen->text().toDouble(&ok);
if (!ok) return false;
return true;
}
void DialogAlgoarg::on_btn_camer_ok_clicked()
{
if (SaveConfigFromUI()) {
StyledMessageBox::information(this, "成功", "配置保存成功!");
accept();
} else {
StyledMessageBox::warning(this, "失败", "配置保存失败,请检查文件权限或参数输入!");
}
}
void DialogAlgoarg::on_btn_camer_cancel_clicked()
{
reject();
}
void DialogAlgoarg::on_btn_loadCalibMatrix_clicked()
{
QString filePath = QFileDialog::getOpenFileName(
this,
"选择手眼标定文件",
QString(),
"INI文件 (*.ini);;所有文件 (*.*)"
);
if (filePath.isEmpty()) {
return;
}
LoadCalibMatrixFromFile(filePath);
StyledMessageBox::information(this, "提示", "已从文件导入标定矩阵");
}
QLineEdit* DialogAlgoarg::GetCalibLineEdit(int row, int col)
{
// 通过名称查找对应的QLineEdit
QString name = QString("lineEdit_calib_%1_%2").arg(row).arg(col);
return findChild<QLineEdit*>(name);
}
void DialogAlgoarg::LoadCalibMatrixToUI()
{
if (!m_pConfigManager) return;
ConfigResult configData = m_pConfigManager->GetConfigResult();
for (int i = 0; i < 16; i++) {
QLineEdit* edit = GetCalibLineEdit(i / 4, i % 4);
if (edit) {
edit->setText(QString::number(configData.handEyeCalibMatrix.matrix[i], 'f', 6));
}
}
// 加载旋转顺序
int eulerOrder = configData.handEyeCalibMatrix.eulerOrder;
int index = ui->comboBox_eulerOrder->findData(eulerOrder);
if (index >= 0) {
ui->comboBox_eulerOrder->setCurrentIndex(index);
}
}
void DialogAlgoarg::LoadCalibMatrixFromFile(const QString& filePath)
{
QSettings settings(filePath, QSettings::IniFormat);
settings.beginGroup("CalibMatrixInfo_0");
for (int i = 0; i < 16; i++) {
int row = i / 4;
int col = i % 4;
QString key = QString("dCalibMatrix_%1").arg(i);
double val = settings.value(key, (row == col) ? 1.0 : 0.0).toDouble();
QLineEdit* edit = GetCalibLineEdit(row, col);
if (edit) {
edit->setText(QString::number(val, 'f', 6));
}
}
settings.endGroup();
}
bool DialogAlgoarg::SaveCalibMatrixToConfig(VrHandEyeCalibMatrix& calibMatrix)
{
for (int i = 0; i < 16; i++) {
QLineEdit* edit = GetCalibLineEdit(i / 4, i % 4);
if (!edit) return false;
bool ok = false;
calibMatrix.matrix[i] = edit->text().toDouble(&ok);
if (!ok) return false;
}
// 保存旋转顺序
calibMatrix.eulerOrder = ui->comboBox_eulerOrder->currentData().toInt();
return true;
}
void DialogAlgoarg::InitEulerOrderComboBox()
{
// 添加外旋旋转顺序选项(工业机械臂常用)
ui->comboBox_eulerOrder->addItem("RZ-RY-RX (外旋ZYX)", 11); // ABB、KUKA、发那科等常用
ui->comboBox_eulerOrder->addItem("RX-RY-RZ (外旋XYZ)", 10);
ui->comboBox_eulerOrder->addItem("RZ-RX-RY (外旋ZXY)", 12);
ui->comboBox_eulerOrder->addItem("RY-RX-RZ (外旋YXZ)", 13);
ui->comboBox_eulerOrder->addItem("RY-RZ-RX (外旋YZX)", 14);
ui->comboBox_eulerOrder->addItem("RX-RZ-RY (外旋XZY)", 15);
// 默认选择外旋 ZYX
ui->comboBox_eulerOrder->setCurrentIndex(0);
}
void DialogAlgoarg::InitPoseOutputOrderComboBox()
{
// 添加姿态输出顺序选项
ui->comboBox_poseOutputOrder->addItem("RPY (Roll, Pitch, Yaw)", POSE_ORDER_RPY); // 默认
ui->comboBox_poseOutputOrder->addItem("RYP (Roll, Yaw, Pitch)", POSE_ORDER_RYP);
ui->comboBox_poseOutputOrder->addItem("PRY (Pitch, Roll, Yaw)", POSE_ORDER_PRY);
ui->comboBox_poseOutputOrder->addItem("PYR (Pitch, Yaw, Roll)", POSE_ORDER_PYR);
ui->comboBox_poseOutputOrder->addItem("YRP (Yaw, Roll, Pitch)", POSE_ORDER_YRP);
ui->comboBox_poseOutputOrder->addItem("YPR (Yaw, Pitch, Roll)", POSE_ORDER_YPR);
// 默认选择 RPY
ui->comboBox_poseOutputOrder->setCurrentIndex(0);
}
void DialogAlgoarg::InitDirVectorInvertComboBox()
{
// 添加方向向量反向选项
ui->comboBox_dirVectorInvert->addItem("不反向", DIR_INVERT_NONE);
ui->comboBox_dirVectorInvert->addItem("XY反向", DIR_INVERT_XY);
ui->comboBox_dirVectorInvert->addItem("XZ反向", DIR_INVERT_XZ);
ui->comboBox_dirVectorInvert->addItem("YZ反向默认", DIR_INVERT_YZ);
// 默认选择 YZ反向兼容原有行为
ui->comboBox_dirVectorInvert->setCurrentIndex(3);
}
void DialogAlgoarg::LoadPlcRobotServerConfigToUI(const VrPlcRobotServerConfig& config)
{
if (!ui) return;
// 加载PLC服务端配置
ui->lineEdit_plcServerIp->setText(QString::fromStdString(config.plcServerIp));
ui->lineEdit_plcServerPort->setText(QString::number(config.plcServerPort));
// 加载PLC寄存器地址配置
ui->lineEdit_addrPhotoRequest->setText(QString::number(config.registerConfig.addrPhotoRequest));
ui->lineEdit_addrDataComplete->setText(QString::number(config.registerConfig.addrDataComplete));
ui->lineEdit_addrCoordDataStart->setText(QString::number(config.registerConfig.addrCoordDataStart));
// 加载姿态输出顺序
int poseOrderIndex = ui->comboBox_poseOutputOrder->findData(config.poseOutputOrder);
if (poseOrderIndex >= 0) {
ui->comboBox_poseOutputOrder->setCurrentIndex(poseOrderIndex);
}
// 加载方向向量反向配置
int dirInvertIndex = ui->comboBox_dirVectorInvert->findData(config.dirVectorInvert);
if (dirInvertIndex >= 0) {
ui->comboBox_dirVectorInvert->setCurrentIndex(dirInvertIndex);
}
}
bool DialogAlgoarg::SavePlcRobotServerConfigFromUI(VrPlcRobotServerConfig& config)
{
if (!ui) return false;
// 获取PLC服务端IP
QString plcIp = ui->lineEdit_plcServerIp->text().trimmed();
if (plcIp.isEmpty()) {
return false;
}
config.plcServerIp = plcIp.toStdString();
// 获取PLC服务端端口
bool ok = false;
config.plcServerPort = ui->lineEdit_plcServerPort->text().toInt(&ok);
if (!ok || config.plcServerPort <= 0 || config.plcServerPort > 65535) {
return false;
}
// 获取PLC寄存器地址配置
config.registerConfig.addrPhotoRequest = ui->lineEdit_addrPhotoRequest->text().toInt(&ok);
if (!ok || config.registerConfig.addrPhotoRequest < 0) {
return false;
}
config.registerConfig.addrDataComplete = ui->lineEdit_addrDataComplete->text().toInt(&ok);
if (!ok || config.registerConfig.addrDataComplete < 0) {
return false;
}
config.registerConfig.addrCoordDataStart = ui->lineEdit_addrCoordDataStart->text().toInt(&ok);
if (!ok || config.registerConfig.addrCoordDataStart < 0) {
return false;
}
// 获取姿态输出顺序
config.poseOutputOrder = ui->comboBox_poseOutputOrder->currentData().toInt();
// 获取方向向量反向配置
config.dirVectorInvert = ui->comboBox_dirVectorInvert->currentData().toInt();
return true;
}