414 lines
14 KiB
C++
Raw Normal View History

2026-08-04 14:23:07 +08:00
#include "dialogalgoarg.h"
#include "ui_dialogalgoarg.h"
#include <QMessageBox>
#include <QPushButton>
#include <cstring>
#include <QSettings>
#include <QFileDialog>
#include <QDoubleValidator>
#include <QGroupBox>
#include "PathManager.h"
#include "StyledMessageBox.h"
#include "ToolExtrinsicWidget.h"
#include "NetworkConfigWidget.h"
#include "VrLog.h"
DialogAlgoarg::DialogAlgoarg(ConfigManager* configManager, QWidget *parent)
: QDialog(parent)
, ui(new Ui::DialogAlgoarg)
, m_pConfigManager(configManager)
, m_toolExtrinsicWidget(nullptr)
{
try {
ui->setupUi(this);
ui->lineEdit_modelMinimumScore->setValidator(
new QDoubleValidator(0.0, 1.0, 6, ui->lineEdit_modelMinimumScore));
ui->tabWidget->setCurrentIndex(0);
InitNetworkConfigTab();
InitToolExtrinsicTab();
// 隐藏标题栏
// setWindowFlags(Qt::FramelessWindowHint);
// 获取配置文件路径
m_configFilePath = PathManager::GetInstance().GetConfigFilePath();
// 检查配置文件路径是否有效
if (m_configFilePath.isEmpty()) {
StyledMessageBox::critical(this, "错误", "无法获取配置文件路径!");
return;
}
// 初始化旋转顺序下拉框
InitEulerOrderComboBox();
// 从配置文件加载数据到界面
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");
}
const VrToolParam& toolParam = configData.algorithmParams.toolParam;
LoadModelDetectionParamsToUI(configData.algorithmParams.modelParam);
LoadFullImageCaptureParamsToUI(configData.algorithmParams.fullImageCaptureParam);
if (m_toolExtrinsicWidget) {
m_toolExtrinsicWidget->setData(
toolParam.eulerOrder,
toolParam.rotX, toolParam.rotY, toolParam.rotZ,
toolParam.offsetX, toolParam.offsetY, toolParam.offsetZ);
}
// 加载网络配置JSON TCP 端口 + Modbus 寄存器地址)
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;
LoadModelDetectionParamsToUI(configData.algorithmParams.modelParam);
LoadFullImageCaptureParamsToUI(configData.algorithmParams.fullImageCaptureParam);
const VrToolParam& toolParam = configData.algorithmParams.toolParam;
if (m_toolExtrinsicWidget) {
m_toolExtrinsicWidget->setData(
toolParam.eulerOrder,
toolParam.rotX, toolParam.rotY, toolParam.rotZ,
toolParam.offsetX, toolParam.offsetY, toolParam.offsetZ);
}
} catch (...) {
LOG_ERROR("Unknown exception in LoadConfigToUI\n");
StyledMessageBox::warning(this, "警告", "加载配置文件失败(未知错误),将使用默认参数显示");
ConfigResult configData;
LoadModelDetectionParamsToUI(configData.algorithmParams.modelParam);
LoadFullImageCaptureParamsToUI(configData.algorithmParams.fullImageCaptureParam);
const VrToolParam& toolParam = configData.algorithmParams.toolParam;
if (m_toolExtrinsicWidget) {
m_toolExtrinsicWidget->setData(
toolParam.eulerOrder,
toolParam.rotX, toolParam.rotY, toolParam.rotZ,
toolParam.offsetX, toolParam.offsetY, toolParam.offsetZ);
}
}
}
void DialogAlgoarg::InitToolExtrinsicTab()
{
if (!ui || !ui->verticalLayout_toolExtrinsicHost || m_toolExtrinsicWidget) {
return;
}
m_toolExtrinsicWidget = new ToolExtrinsicWidget(this);
m_toolExtrinsicWidget->setCameraSelectorVisible(false);
m_toolExtrinsicWidget->setTargetOffsetVisible(true);
m_toolExtrinsicWidget->setAxialAngleRangeVisible(false);
ui->verticalLayout_toolExtrinsicHost->addWidget(m_toolExtrinsicWidget);
}
void DialogAlgoarg::InitNetworkConfigTab()
{
if (!ui || !ui->tabWidget || m_networkConfigWidget) {
return;
}
m_networkConfigWidget = new NetworkConfigWidget(true, true, ui->tabWidget);
m_networkConfigWidget->setExtrinsicControlsVisible(false);
m_networkConfigWidget->setPoseOutputOrderVisible(true);
if (QGroupBox* group = m_networkConfigWidget->findChild<QGroupBox*>("groupPlc")) {
group->setTitle(QStringLiteral("TCP端口与Modbus寄存器配置"));
}
const char* hideNames[] = {"labelPlcIp", "editPlcIp", "labelPlcPort", "editPlcPort"};
for (const char* name : hideNames) {
if (QWidget* widget = m_networkConfigWidget->findChild<QWidget*>(name)) {
widget->hide();
}
}
ui->tabWidget->addTab(m_networkConfigWidget, QStringLiteral("网络配置"));
}
bool DialogAlgoarg::SaveConfigFromUI()
{
if (!m_pConfigManager) {
return false;
}
try {
// 获取当前配置
SystemConfig systemConfig = m_pConfigManager->GetConfig();
VrToolParam& toolParam = systemConfig.configResult.algorithmParams.toolParam;
if (!SaveModelDetectionParamsFromUI(
systemConfig.configResult.algorithmParams.modelParam)) {
StyledMessageBox::warning(this, "错误", "模型检测参数输入有误,请检查!");
return false;
}
if (!SaveFullImageCaptureParamsFromUI(
systemConfig.configResult.algorithmParams.fullImageCaptureParam)) {
StyledMessageBox::warning(this, "错误", "二维全图采集参数输入有误,请检查!");
return false;
}
if (!m_toolExtrinsicWidget || !m_toolExtrinsicWidget->hasAcceptableInput()) {
StyledMessageBox::warning(this, "错误", "工具参数输入有误,请检查!");
return false;
}
m_toolExtrinsicWidget->getData(
toolParam.eulerOrder,
toolParam.rotX, toolParam.rotY, toolParam.rotZ,
toolParam.offsetX, toolParam.offsetY, toolParam.offsetZ);
// 保存网络配置JSON TCP 端口 + Modbus 寄存器地址)
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&) {
return false;
}
}
void DialogAlgoarg::LoadModelDetectionParamsToUI(const VrWorkpieceModelParam& modelParam)
{
if (!ui || !ui->lineEdit_modelMinimumScore) {
return;
}
ui->lineEdit_modelMinimumScore->setText(QString::number(modelParam.minimumScore, 'f', 6));
}
bool DialogAlgoarg::SaveModelDetectionParamsFromUI(VrWorkpieceModelParam& modelParam)
{
if (!ui || !ui->lineEdit_modelMinimumScore) {
return false;
}
bool scoreOk = false;
const double minimumScore = ui->lineEdit_modelMinimumScore->text().toDouble(&scoreOk);
if (!scoreOk || minimumScore < 0.0 || minimumScore > 1.0) {
return false;
}
modelParam.minimumScore = minimumScore;
return true;
}
void DialogAlgoarg::LoadFullImageCaptureParamsToUI(const VrFullImageCaptureParam& captureParam)
{
if (!ui || !ui->lineEdit_fullImageExposure || !ui->lineEdit_fullImageGain) {
return;
}
ui->lineEdit_fullImageExposure->setText(QString::number(captureParam.exposure));
ui->lineEdit_fullImageGain->setText(QString::number(captureParam.gain));
}
bool DialogAlgoarg::SaveFullImageCaptureParamsFromUI(VrFullImageCaptureParam& captureParam)
{
if (!ui || !ui->lineEdit_fullImageExposure || !ui->lineEdit_fullImageGain) {
return false;
}
bool exposureOk = false;
bool gainOk = false;
const unsigned int exposure = ui->lineEdit_fullImageExposure->text().toUInt(&exposureOk);
const unsigned int gain = ui->lineEdit_fullImageGain->text().toUInt(&gainOk);
if (!exposureOk || exposure == 0 || !gainOk) {
return false;
}
captureParam.exposure = exposure;
captureParam.gain = gain;
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::LoadPlcRobotServerConfigToUI(const VrPlcRobotServerConfig& config)
{
if (!m_networkConfigWidget) return;
NetworkConfigData data;
data.poseOutputOrder = config.poseOutputOrder;
data.byteOrder = config.byteOrder;
data.dirVectorInvert = config.dirVectorInvert;
data.addrPhotoRequest = config.registerConfig.addrTrigger;
data.addrDataComplete = config.registerConfig.addrWorkStatus;
data.addrCoordDataStart = config.registerConfig.addrCoordDataStart;
data.tcpServerPort = config.robotServerPort;
m_networkConfigWidget->setConfig(data);
}
bool DialogAlgoarg::SavePlcRobotServerConfigFromUI(VrPlcRobotServerConfig& config)
{
if (!m_networkConfigWidget) return false;
const NetworkConfigData data = m_networkConfigWidget->getConfig();
if (data.tcpServerPort <= 0 || data.tcpServerPort > 65535 ||
data.addrPhotoRequest < 0 ||
data.addrDataComplete < 0 ||
data.addrCoordDataStart < 0) {
return false;
}
config.robotServerPort = data.tcpServerPort;
config.registerConfig.addrTrigger = data.addrPhotoRequest;
config.registerConfig.addrWorkStatus = data.addrDataComplete;
config.registerConfig.addrCoordDataStart = data.addrCoordDataStart;
config.poseOutputOrder = data.poseOutputOrder;
config.dirVectorInvert = data.dirVectorInvert;
config.byteOrder = data.byteOrder;
return true;
}