566 lines
21 KiB
C++
566 lines
21 KiB
C++
#include "dialogalgoarg.h"
|
||
#include "ui_dialogalgoarg.h"
|
||
|
||
#include "HandEyeCalibWidget.h"
|
||
#include "NetworkConfigWidget.h"
|
||
#include "ToolExtrinsicWidget.h"
|
||
#include "PathManager.h"
|
||
#include "JiuruiWorkpiecePosePresenter.h"
|
||
#include "StyledMessageBox.h"
|
||
|
||
#include <QDoubleValidator>
|
||
#include <QGroupBox>
|
||
#include <QIntValidator>
|
||
#include <QLabel>
|
||
#include <QLineEdit>
|
||
|
||
#include <algorithm>
|
||
#include <cmath>
|
||
#include <cstring>
|
||
|
||
namespace {
|
||
|
||
bool IsIdentityMatrix(const double matrix[16])
|
||
{
|
||
for (int i = 0; i < 16; ++i) {
|
||
const double expected = (i / 4 == i % 4) ? 1.0 : 0.0;
|
||
if (std::fabs(matrix[i] - expected) > 1e-9) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
} // namespace
|
||
|
||
DialogAlgoArg::DialogAlgoArg(QWidget *parent)
|
||
: QDialog(parent)
|
||
, ui(new Ui::DialogAlgoArg)
|
||
{
|
||
ui->setupUi(this);
|
||
setWindowTitle(QStringLiteral("工件定位 - 算法参数设置"));
|
||
|
||
initNumericEditors();
|
||
initWorkpieceParamEditors();
|
||
initHandEyeCalibTab();
|
||
initNetworkConfigTab();
|
||
}
|
||
|
||
DialogAlgoArg::~DialogAlgoArg()
|
||
{
|
||
delete ui;
|
||
}
|
||
|
||
void DialogAlgoArg::SetPresenter(JiuruiWorkpiecePosePresenter* presenter)
|
||
{
|
||
m_presenter = presenter;
|
||
loadParams();
|
||
loadHandEyeCalibConfig();
|
||
// 配置工具参数控件
|
||
ui->toolExtrinsicWidget->setTargetOffsetVisible(true);
|
||
ui->toolExtrinsicWidget->setAxialAngleRangeVisible(true);
|
||
loadToolExtrinsicConfig();
|
||
loadNetworkConfig();
|
||
}
|
||
|
||
void DialogAlgoArg::initNumericEditors()
|
||
{
|
||
auto setupDoubleEditor = [](QLineEdit* edit, double min, double max, int decimals) {
|
||
auto* validator = new QDoubleValidator(min, max, decimals, edit);
|
||
validator->setNotation(QDoubleValidator::StandardNotation);
|
||
edit->setValidator(validator);
|
||
};
|
||
|
||
// 角点检测的 6 个参数
|
||
setupDoubleEditor(ui->spinCornerTh, 0.0, 180.0, 6);
|
||
setupDoubleEditor(ui->spinScale, 0.0, 200.0, 6);
|
||
setupDoubleEditor(ui->spinMinEndingGap, 0.0, 100.0, 6);
|
||
setupDoubleEditor(ui->spinMinEndingGapZ, 0.0, 100.0, 6);
|
||
setupDoubleEditor(ui->spinJumpCornerTh1, 0.0, 100.0, 6);
|
||
setupDoubleEditor(ui->spinJumpCornerTh2, 0.0, 180.0, 6);
|
||
}
|
||
|
||
void DialogAlgoArg::initWorkpieceParamEditors()
|
||
{
|
||
// 在 tabWidget 中新增独立的"工件参数"Tab 页
|
||
if (!ui->tabWidget || m_editWpLength) {
|
||
return;
|
||
}
|
||
|
||
// 创建 Tab 页容器
|
||
auto* tabWorkpiece = new QWidget();
|
||
tabWorkpiece->setObjectName(QStringLiteral("tabWorkpiece"));
|
||
tabWorkpiece->setStyleSheet(ui->tabCorner->styleSheet());
|
||
|
||
// 工件参数 GroupBox(三个参数:长、宽、厚)
|
||
auto* groupBoxWorkpiece = new QGroupBox(QStringLiteral("工件参数 (WD_JiuruiWorkpieceParam)"), tabWorkpiece);
|
||
groupBoxWorkpiece->setGeometry(10, 20, 671, 260);
|
||
QFont groupFont = ui->groupBox_corner->font();
|
||
groupBoxWorkpiece->setFont(groupFont);
|
||
|
||
// 工件长度
|
||
auto* labelLength = new QLabel(QStringLiteral("工件长度(len):"), groupBoxWorkpiece);
|
||
labelLength->setGeometry(30, 50, 220, 32);
|
||
labelLength->setFont(groupFont);
|
||
|
||
m_editWpLength = new QLineEdit(groupBoxWorkpiece);
|
||
m_editWpLength->setObjectName(QStringLiteral("spinWpLength"));
|
||
m_editWpLength->setGeometry(280, 50, 200, 35);
|
||
m_editWpLength->setFont(groupFont);
|
||
m_editWpLength->setText(QStringLiteral("320"));
|
||
|
||
// 工件宽度
|
||
auto* labelWidth = new QLabel(QStringLiteral("工件宽度(width):"), groupBoxWorkpiece);
|
||
labelWidth->setGeometry(30, 110, 220, 32);
|
||
labelWidth->setFont(groupFont);
|
||
|
||
m_editWpWidth = new QLineEdit(groupBoxWorkpiece);
|
||
m_editWpWidth->setObjectName(QStringLiteral("spinWpWidth"));
|
||
m_editWpWidth->setGeometry(280, 110, 200, 35);
|
||
m_editWpWidth->setFont(groupFont);
|
||
m_editWpWidth->setText(QStringLiteral("140"));
|
||
|
||
// 工件厚度
|
||
auto* labelThicknessWp = new QLabel(QStringLiteral("工件厚度(thickness):"), groupBoxWorkpiece);
|
||
labelThicknessWp->setGeometry(30, 170, 220, 32);
|
||
labelThicknessWp->setFont(groupFont);
|
||
|
||
m_editWpThickness = new QLineEdit(groupBoxWorkpiece);
|
||
m_editWpThickness->setObjectName(QStringLiteral("spinWpThickness"));
|
||
m_editWpThickness->setGeometry(280, 170, 200, 35);
|
||
m_editWpThickness->setFont(groupFont);
|
||
m_editWpThickness->setText(QStringLiteral("48"));
|
||
|
||
// 设置验证器
|
||
auto setupDouble = [](QLineEdit* edit, double min, double max, int decimals) {
|
||
auto* validator = new QDoubleValidator(min, max, decimals, edit);
|
||
validator->setNotation(QDoubleValidator::StandardNotation);
|
||
edit->setValidator(validator);
|
||
};
|
||
setupDouble(m_editWpLength, 0.0, 10000.0, 6);
|
||
setupDouble(m_editWpWidth, 0.0, 10000.0, 6);
|
||
setupDouble(m_editWpThickness, 0.0, 10000.0, 6);
|
||
|
||
// 在"角点检测"Tab 之后插入"工件参数"Tab(索引 1)
|
||
ui->tabWidget->insertTab(1, tabWorkpiece, QStringLiteral("工件参数"));
|
||
}
|
||
|
||
void DialogAlgoArg::initHandEyeCalibTab()
|
||
{
|
||
if (!ui || !ui->verticalLayout_handEyeCalibHost || m_handEyeCalibWidget) {
|
||
return;
|
||
}
|
||
|
||
m_handEyeCalibWidget = new HandEyeCalibWidget(this);
|
||
m_handEyeCalibWidget->setMatrixEditable(true);
|
||
m_handEyeCalibWidget->setExtrinsicControlsVisible(true);
|
||
m_handEyeCalibWidget->setDefaultFilePath(PathManager::GetInstance().GetAppConfigDirectory());
|
||
ui->verticalLayout_handEyeCalibHost->addWidget(m_handEyeCalibWidget);
|
||
|
||
connect(m_handEyeCalibWidget, &HandEyeCalibWidget::calibMatrixLoaded,
|
||
this, &DialogAlgoArg::onCalibMatrixLoaded);
|
||
connect(m_handEyeCalibWidget, &HandEyeCalibWidget::saveCalibRequested,
|
||
this, &DialogAlgoArg::onSaveCalibRequested);
|
||
}
|
||
|
||
void DialogAlgoArg::initNetworkConfigTab()
|
||
{
|
||
if (!ui || !ui->verticalLayout_networkConfigHost || m_networkConfigWidget) {
|
||
return;
|
||
}
|
||
|
||
m_networkConfigWidget = new NetworkConfigWidget(false, true, this);
|
||
m_networkConfigWidget->setExtrinsicControlsVisible(true);
|
||
ui->verticalLayout_networkConfigHost->addWidget(m_networkConfigWidget);
|
||
}
|
||
|
||
void DialogAlgoArg::setDoubleEditorText(QLineEdit* edit, double value)
|
||
{
|
||
if (edit) {
|
||
edit->setText(QString::number(value, 'g', 12));
|
||
}
|
||
}
|
||
|
||
void DialogAlgoArg::setIntEditorText(QLineEdit* edit, int value)
|
||
{
|
||
if (edit) {
|
||
edit->setText(QString::number(value));
|
||
}
|
||
}
|
||
|
||
bool DialogAlgoArg::tryGetDouble(QLineEdit* edit, const QString& label, double& value)
|
||
{
|
||
bool ok = false;
|
||
value = edit->text().trimmed().toDouble(&ok);
|
||
if (!ok) {
|
||
StyledMessageBox::warning(this, QStringLiteral("错误"),
|
||
QStringLiteral("\"%1\" 输入的数值无效。").arg(label));
|
||
edit->setFocus();
|
||
edit->selectAll();
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool DialogAlgoArg::tryGetInt(QLineEdit* edit, const QString& label, int& value)
|
||
{
|
||
bool ok = false;
|
||
value = edit->text().trimmed().toInt(&ok);
|
||
if (!ok) {
|
||
StyledMessageBox::warning(this, QStringLiteral("错误"),
|
||
QStringLiteral("\"%1\" 输入的整数无效。").arg(label));
|
||
edit->setFocus();
|
||
edit->selectAll();
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void DialogAlgoArg::loadParams()
|
||
{
|
||
if (!m_presenter || !m_presenter->GetConfigManager()) {
|
||
return;
|
||
}
|
||
|
||
const ConfigResult configResult = m_presenter->GetConfigManager()->GetConfigResult();
|
||
const VrCornerParam corner = configResult.algorithmParams.cornerParam;
|
||
const VrJiuruiWorkpieceParam wp = configResult.algorithmParams.workpieceParam;
|
||
|
||
setDoubleEditorText(ui->spinCornerTh, corner.cornerTh);
|
||
setDoubleEditorText(ui->spinScale, corner.scale);
|
||
setDoubleEditorText(ui->spinMinEndingGap, corner.minEndingGap);
|
||
setDoubleEditorText(ui->spinMinEndingGapZ, corner.minEndingGap_z);
|
||
setDoubleEditorText(ui->spinJumpCornerTh1, corner.jumpCornerTh_1);
|
||
setDoubleEditorText(ui->spinJumpCornerTh2, corner.jumpCornerTh_2);
|
||
|
||
setDoubleEditorText(m_editWpLength, wp.len);
|
||
setDoubleEditorText(m_editWpWidth, wp.width);
|
||
setDoubleEditorText(m_editWpThickness, wp.thickness);
|
||
}
|
||
|
||
void DialogAlgoArg::loadHandEyeCalibConfig()
|
||
{
|
||
if (!m_presenter || !m_handEyeCalibWidget || !m_presenter->GetConfigManager()) {
|
||
return;
|
||
}
|
||
|
||
const ConfigResult configResult = m_presenter->GetConfigManager()->GetConfigResult();
|
||
QVector<HandEyeCalibCameraInfo> cameraInfos;
|
||
if (configResult.cameraList.empty()) {
|
||
HandEyeCalibCameraInfo defaultCam;
|
||
defaultCam.cameraIndex = 1;
|
||
defaultCam.displayName = QStringLiteral("相机 1");
|
||
cameraInfos.append(defaultCam);
|
||
} else {
|
||
for (size_t i = 0; i < configResult.cameraList.size(); ++i) {
|
||
HandEyeCalibCameraInfo info;
|
||
info.cameraIndex = static_cast<int>(i + 1);
|
||
info.displayName = QString::fromStdString(configResult.cameraList[i].name);
|
||
cameraInfos.append(info);
|
||
}
|
||
}
|
||
|
||
m_handEyeCalibWidget->setCameraList(cameraInfos);
|
||
|
||
for (const auto& info : cameraInfos) {
|
||
const VrHandEyeCalibMatrix* savedMatrix =
|
||
configResult.FindHandEyeMatrix(info.cameraIndex);
|
||
|
||
if (savedMatrix) {
|
||
m_handEyeCalibWidget->setCalibData(info.cameraIndex,
|
||
savedMatrix->matrix,
|
||
!IsIdentityMatrix(savedMatrix->matrix));
|
||
m_handEyeCalibWidget->setExtrinsicData(info.cameraIndex,
|
||
savedMatrix->eulerOrder,
|
||
savedMatrix->rotX,
|
||
savedMatrix->rotY,
|
||
savedMatrix->rotZ,
|
||
savedMatrix->approachOffset,
|
||
savedMatrix->offsetX,
|
||
savedMatrix->offsetY,
|
||
savedMatrix->offsetZ);
|
||
} else {
|
||
const CalibMatrix calibMatrix = m_presenter->GetClibMatrix(info.cameraIndex - 1);
|
||
m_handEyeCalibWidget->setCalibData(info.cameraIndex,
|
||
calibMatrix.clibMatrix,
|
||
!IsIdentityMatrix(calibMatrix.clibMatrix));
|
||
m_handEyeCalibWidget->setExtrinsicData(info.cameraIndex, 11, 0.0, 0.0, 0.0, 0.0);
|
||
}
|
||
}
|
||
}
|
||
|
||
void DialogAlgoArg::loadNetworkConfig()
|
||
{
|
||
if (!m_presenter || !m_presenter->GetConfigManager() || !m_networkConfigWidget) {
|
||
return;
|
||
}
|
||
|
||
const ConfigResult configResult = m_presenter->GetConfigManager()->GetConfigResult();
|
||
|
||
NetworkConfigData netConfig;
|
||
netConfig.tcpServerPort = configResult.tcpPort;
|
||
netConfig.eulerOrder = configResult.eulerOrder;
|
||
netConfig.outputEulerOrder = configResult.outputEulerOrder;
|
||
netConfig.poseOutputOrder = configResult.poseOutputOrder;
|
||
netConfig.byteOrder = configResult.byteOrder;
|
||
|
||
m_networkConfigWidget->setConfig(netConfig);
|
||
}
|
||
|
||
bool DialogAlgoArg::saveParams()
|
||
{
|
||
if (!m_presenter || !m_presenter->GetConfigManager()) {
|
||
return false;
|
||
}
|
||
|
||
SystemConfig systemConfig = m_presenter->GetConfigManager()->GetConfig();
|
||
|
||
// —— 读取共享算法参数 ——
|
||
|
||
VrCornerParam& corner = systemConfig.configResult.algorithmParams.cornerParam;
|
||
if (!tryGetDouble(ui->spinCornerTh, QStringLiteral("拐角阈值"), corner.cornerTh)) return false;
|
||
if (!tryGetDouble(ui->spinScale, QStringLiteral("窗口比例因子"), corner.scale)) return false;
|
||
if (!tryGetDouble(ui->spinMinEndingGap, QStringLiteral("Y方向最小结束间隙"), corner.minEndingGap)) return false;
|
||
if (!tryGetDouble(ui->spinMinEndingGapZ, QStringLiteral("Z方向最小结束间隙"), corner.minEndingGap_z)) return false;
|
||
if (!tryGetDouble(ui->spinJumpCornerTh1, QStringLiteral("跳变拐角阈值1"), corner.jumpCornerTh_1)) return false;
|
||
if (!tryGetDouble(ui->spinJumpCornerTh2, QStringLiteral("跳变拐角阈值2"), corner.jumpCornerTh_2)) return false;
|
||
|
||
VrJiuruiWorkpieceParam& wp = systemConfig.configResult.algorithmParams.workpieceParam;
|
||
if (!tryGetDouble(m_editWpLength, QStringLiteral("工件长度"), wp.len)) return false;
|
||
if (!tryGetDouble(m_editWpWidth, QStringLiteral("工件宽度"), wp.width)) return false;
|
||
if (!tryGetDouble(m_editWpThickness, QStringLiteral("工件厚度"), wp.thickness)) return false;
|
||
|
||
// —— 保存手眼标定矩阵到 handEyeCalibMatrixList ——
|
||
|
||
if (m_handEyeCalibWidget) {
|
||
const int cameraCount = std::max(1, static_cast<int>(systemConfig.configResult.cameraList.size()));
|
||
for (int camIdx = 1; camIdx <= cameraCount; ++camIdx) {
|
||
systemConfig.configResult.EnsureHandEyeMatrix(camIdx);
|
||
}
|
||
|
||
for (int camIdx = 1; camIdx <= cameraCount; ++camIdx) {
|
||
bool isCalibrated = false;
|
||
double matrix[16];
|
||
int eulerOrder = 11;
|
||
double rotX = 0.0, rotY = 0.0, rotZ = 0.0;
|
||
double approachOffset = 0.0;
|
||
double offsetX = 0.0, offsetY = 0.0, offsetZ = 0.0;
|
||
const bool hasMatrix = m_handEyeCalibWidget->getCalibData(camIdx, matrix, isCalibrated) && isCalibrated;
|
||
const bool hasExtrinsic = m_handEyeCalibWidget->getExtrinsicData(
|
||
camIdx, eulerOrder, rotX, rotY, rotZ, approachOffset, offsetX, offsetY, offsetZ);
|
||
|
||
VrHandEyeCalibMatrix* hePtr = systemConfig.configResult.FindHandEyeMatrix(camIdx);
|
||
if (!hePtr) {
|
||
systemConfig.configResult.EnsureHandEyeMatrix(camIdx);
|
||
hePtr = systemConfig.configResult.FindHandEyeMatrix(camIdx);
|
||
}
|
||
|
||
if (hePtr) {
|
||
hePtr->cameraIndex = camIdx;
|
||
if (hasMatrix) {
|
||
std::memcpy(hePtr->matrix, matrix, sizeof(double) * 16);
|
||
}
|
||
if (hasExtrinsic) {
|
||
hePtr->eulerOrder = eulerOrder;
|
||
hePtr->rotX = rotX;
|
||
hePtr->rotY = rotY;
|
||
hePtr->rotZ = rotZ;
|
||
hePtr->offsetX = offsetX;
|
||
hePtr->offsetY = offsetY;
|
||
hePtr->offsetZ = offsetZ;
|
||
}
|
||
|
||
// 从工具参数控件获取该相机的工具外参
|
||
if (ui->toolExtrinsicWidget) {
|
||
int toolEulerOrder = hePtr->eulerOrder;
|
||
double toolRotX = hePtr->rotX;
|
||
double toolRotY = hePtr->rotY;
|
||
double toolRotZ = hePtr->rotZ;
|
||
double toolOffsetX = hePtr->offsetX;
|
||
double toolOffsetY = hePtr->offsetY;
|
||
double toolOffsetZ = hePtr->offsetZ;
|
||
double axialAngleMin = hePtr->axialAngleMin;
|
||
double axialAngleMax = hePtr->axialAngleMax;
|
||
if (ui->toolExtrinsicWidget->getData(camIdx,
|
||
toolEulerOrder,
|
||
toolRotX, toolRotY, toolRotZ,
|
||
toolOffsetX, toolOffsetY, toolOffsetZ,
|
||
axialAngleMin, axialAngleMax)) {
|
||
hePtr->eulerOrder = toolEulerOrder;
|
||
hePtr->rotX = toolRotX;
|
||
hePtr->rotY = toolRotY;
|
||
hePtr->rotZ = toolRotZ;
|
||
hePtr->offsetX = toolOffsetX;
|
||
hePtr->offsetY = toolOffsetY;
|
||
hePtr->offsetZ = toolOffsetZ;
|
||
hePtr->axialAngleMin = axialAngleMin;
|
||
hePtr->axialAngleMax = axialAngleMax;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// —— 网络配置 ——
|
||
|
||
if (m_networkConfigWidget) {
|
||
const NetworkConfigData netConfig = m_networkConfigWidget->getConfig();
|
||
if (netConfig.tcpServerPort <= 0 || netConfig.tcpServerPort > 65535) {
|
||
StyledMessageBox::warning(this, QStringLiteral("错误"),
|
||
QStringLiteral("TCP端口必须在 1 到 65535 之间。"));
|
||
return false;
|
||
}
|
||
|
||
systemConfig.configResult.tcpPort = static_cast<uint16_t>(netConfig.tcpServerPort);
|
||
systemConfig.configResult.eulerOrder = netConfig.eulerOrder;
|
||
systemConfig.configResult.outputEulerOrder = netConfig.outputEulerOrder;
|
||
systemConfig.configResult.poseOutputOrder = netConfig.poseOutputOrder;
|
||
systemConfig.configResult.byteOrder = netConfig.byteOrder;
|
||
}
|
||
|
||
if (!m_presenter->GetConfigManager()->UpdateFullConfig(systemConfig)) {
|
||
StyledMessageBox::warning(this, QStringLiteral("失败"),
|
||
QStringLiteral("更新配置缓存失败。"));
|
||
return false;
|
||
}
|
||
|
||
const QString configPath = PathManager::GetInstance().GetConfigFilePath();
|
||
if (!m_presenter->GetConfigManager()->SaveConfigToFile(configPath.toStdString())) {
|
||
StyledMessageBox::warning(this, QStringLiteral("失败"),
|
||
QStringLiteral("保存配置文件失败。"));
|
||
return false;
|
||
}
|
||
|
||
m_presenter->OnConfigChanged(systemConfig.configResult);
|
||
return true;
|
||
}
|
||
|
||
void DialogAlgoArg::resetParams()
|
||
{
|
||
setDoubleEditorText(ui->spinCornerTh, 60.0);
|
||
setDoubleEditorText(ui->spinScale, 10.0);
|
||
setDoubleEditorText(ui->spinMinEndingGap, 10.0);
|
||
setDoubleEditorText(ui->spinMinEndingGapZ, 5.0);
|
||
setDoubleEditorText(ui->spinJumpCornerTh1, 15.0);
|
||
setDoubleEditorText(ui->spinJumpCornerTh2, 60.0);
|
||
setDoubleEditorText(m_editWpLength, 320.0);
|
||
setDoubleEditorText(m_editWpWidth, 140.0);
|
||
setDoubleEditorText(m_editWpThickness, 48.0);
|
||
}
|
||
|
||
void DialogAlgoArg::on_btnOK_clicked()
|
||
{
|
||
if (saveParams()) {
|
||
accept();
|
||
}
|
||
}
|
||
|
||
void DialogAlgoArg::on_btnCancel_clicked()
|
||
{
|
||
reject();
|
||
}
|
||
|
||
void DialogAlgoArg::on_btnApply_clicked()
|
||
{
|
||
if (saveParams()) {
|
||
StyledMessageBox::information(this, QStringLiteral("提示"),
|
||
QStringLiteral("参数已应用。"));
|
||
}
|
||
}
|
||
|
||
void DialogAlgoArg::on_btnReset_clicked()
|
||
{
|
||
const auto ret = StyledMessageBox::question(this, QStringLiteral("确认重置"),
|
||
QStringLiteral("确定要重置为默认参数吗?"), QMessageBox::Yes | QMessageBox::No);
|
||
if (ret == QMessageBox::Yes) {
|
||
resetParams();
|
||
}
|
||
}
|
||
|
||
void DialogAlgoArg::onCalibMatrixLoaded(int cameraIndex, const double* matrix)
|
||
{
|
||
Q_UNUSED(cameraIndex);
|
||
Q_UNUSED(matrix);
|
||
StyledMessageBox::information(this, QStringLiteral("提示"),
|
||
QStringLiteral("已从文件导入手眼标定矩阵。"));
|
||
}
|
||
|
||
void DialogAlgoArg::onSaveCalibRequested(int cameraIndex, const double* matrix)
|
||
{
|
||
Q_UNUSED(cameraIndex);
|
||
Q_UNUSED(matrix);
|
||
|
||
if (saveParams()) {
|
||
StyledMessageBox::information(this, QStringLiteral("成功"),
|
||
QStringLiteral("手眼标定参数已保存。"));
|
||
} else {
|
||
StyledMessageBox::warning(this, QStringLiteral("失败"),
|
||
QStringLiteral("保存手眼标定参数失败。"));
|
||
}
|
||
}
|
||
|
||
// ========== 工具参数相关实现 ==========
|
||
|
||
void DialogAlgoArg::loadToolExtrinsicConfig()
|
||
{
|
||
if (!m_presenter || !ui->toolExtrinsicWidget) return;
|
||
|
||
ConfigManager* configManager = m_presenter->GetConfigManager();
|
||
if (!configManager) return;
|
||
|
||
const ConfigResult configResult = configManager->GetConfigResult();
|
||
const auto& cameraList = configResult.cameraList;
|
||
int cameraCount = std::max(1, static_cast<int>(cameraList.size()));
|
||
|
||
// 设置相机列表
|
||
QVector<ToolExtrinsicCameraInfo> toolCameraList;
|
||
for (size_t i = 0; i < cameraList.size(); ++i) {
|
||
ToolExtrinsicCameraInfo info;
|
||
info.cameraIndex = static_cast<int>(i + 1);
|
||
info.displayName = QString::fromStdString(cameraList[i].name);
|
||
toolCameraList.append(info);
|
||
}
|
||
if (toolCameraList.empty()) {
|
||
ToolExtrinsicCameraInfo defaultCam;
|
||
defaultCam.cameraIndex = 1;
|
||
defaultCam.displayName = QString::fromUtf8("相机 1");
|
||
toolCameraList.append(defaultCam);
|
||
}
|
||
ui->toolExtrinsicWidget->setCameraList(toolCameraList);
|
||
|
||
// 加载每台相机的工具参数
|
||
for (int i = 0; i < cameraCount; ++i) {
|
||
int camIdx = i + 1;
|
||
int toolEulerOrder = 11;
|
||
double rotX = 0.0;
|
||
double rotY = 0.0;
|
||
double rotZ = 0.0;
|
||
double offsetX = 0.0;
|
||
double offsetY = 0.0;
|
||
double offsetZ = 0.0;
|
||
double axialAngleMin = -180.0;
|
||
double axialAngleMax = 180.0;
|
||
|
||
for (const auto& toolConfig : configResult.handEyeCalibMatrixList) {
|
||
if (toolConfig.cameraIndex == camIdx) {
|
||
toolEulerOrder = toolConfig.eulerOrder;
|
||
rotX = toolConfig.rotX;
|
||
rotY = toolConfig.rotY;
|
||
rotZ = toolConfig.rotZ;
|
||
offsetX = toolConfig.offsetX;
|
||
offsetY = toolConfig.offsetY;
|
||
offsetZ = toolConfig.offsetZ;
|
||
axialAngleMin = toolConfig.axialAngleMin;
|
||
axialAngleMax = toolConfig.axialAngleMax;
|
||
break;
|
||
}
|
||
}
|
||
|
||
ui->toolExtrinsicWidget->setData(camIdx,
|
||
toolEulerOrder,
|
||
rotX, rotY, rotZ,
|
||
offsetX, offsetY, offsetZ,
|
||
axialAngleMin, axialAngleMax);
|
||
}
|
||
}
|