GrabBag/Tools/CalibView/Src/CalibDataWidget.cpp
2026-03-29 10:48:35 +08:00

1038 lines
44 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 "CalibDataWidget.h"
#include "../../SpinBoxPasteHelper.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSettings>
#include <QDateTime>
#include <QGridLayout>
#include <QHeaderView>
#include <QLabel>
#include <array>
CalibDataWidget::CalibDataWidget(QWidget* parent)
: QWidget(parent)
, m_cbCalibType(nullptr)
, m_cbEulerOrder(nullptr)
, m_tableHandEye(nullptr)
, m_groupHandEye(nullptr)
, m_btnHandEyeAddRow(nullptr)
, m_btnHandEyeDeleteRow(nullptr)
, m_btnHandEyeCalib(nullptr)
, m_groupTCPCalib(nullptr)
, m_tableTCP(nullptr)
, m_tcpModeCombo(nullptr)
, m_tcpEulerOrderCombo(nullptr)
, m_tcpRefPoseIndex(nullptr)
, m_tcpWorldRx(nullptr)
, m_tcpWorldRy(nullptr)
, m_tcpWorldRz(nullptr)
, m_tcpOrientationGroup(nullptr)
, m_tcpAddRowBtn(nullptr)
, m_tcpRemoveRowBtn(nullptr)
, m_btnTCPCalib(nullptr)
, m_inputCamX(nullptr)
, m_inputCamY(nullptr)
, m_inputCamZ(nullptr)
, m_inputCamRoll(nullptr)
, m_inputCamPitch(nullptr)
, m_inputCamYaw(nullptr)
, m_inputRobotX(nullptr)
, m_inputRobotY(nullptr)
, m_inputRobotZ(nullptr)
, m_inputRobotRoll(nullptr)
, m_inputRobotPitch(nullptr)
, m_inputRobotYaw(nullptr)
, m_btnHandEyeAddInput(nullptr)
, m_inputTcpX(nullptr)
, m_inputTcpY(nullptr)
, m_inputTcpZ(nullptr)
, m_inputTcpRx(nullptr)
, m_inputTcpRy(nullptr)
, m_inputTcpRz(nullptr)
, m_btnTcpAddInput(nullptr)
, m_cbCamAngleUnit(nullptr)
, m_lblCamRx(nullptr)
, m_lblCamRy(nullptr)
, m_lblCamRz(nullptr)
{
setupUI();
SpinBoxPasteHelper::install(this);
}
CalibDataWidget::~CalibDataWidget()
{
}
void CalibDataWidget::setupUI()
{
QVBoxLayout* mainLayout = new QVBoxLayout(this);
// 标定模式选择
QHBoxLayout* modeLayout = new QHBoxLayout();
QLabel* lblMode = new QLabel("标定模式:", this);
m_cbCalibType = new QComboBox(this);
m_cbCalibType->addItem("Eye-To-Hand (眼在手外)");
m_cbCalibType->addItem("Eye-In-Hand (眼在手上)");
m_cbCalibType->addItem("TCP 标定");
connect(m_cbCalibType, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CalibDataWidget::onCalibTypeChanged);
modeLayout->addWidget(lblMode);
modeLayout->addWidget(m_cbCalibType);
// 欧拉角顺序选择
modeLayout->addSpacing(20);
QLabel* lblEuler = new QLabel("欧拉角顺序:", this);
m_cbEulerOrder = new QComboBox(this);
m_cbEulerOrder->addItem("ZYX (默认)");
m_cbEulerOrder->addItem("XYZ");
m_cbEulerOrder->addItem("XZY");
m_cbEulerOrder->addItem("YXZ");
m_cbEulerOrder->addItem("YZX");
m_cbEulerOrder->addItem("ZXY");
modeLayout->addWidget(lblEuler);
modeLayout->addWidget(m_cbEulerOrder);
modeLayout->addStretch();
mainLayout->addLayout(modeLayout);
// 手眼标定数据组Eye-To-Hand 和 Eye-In-Hand 共用)
m_groupHandEye = createHandEyeGroup();
mainLayout->addWidget(m_groupHandEye, 1);
// TCP 标定数据组
m_groupTCPCalib = createTCPCalibGroup();
mainLayout->addWidget(m_groupTCPCalib, 1);
m_groupTCPCalib->setVisible(false);
// 初始化按钮启用状态
onCalibTypeChanged(0);
}
QWidget* CalibDataWidget::createHandEyeGroup()
{
QWidget* group = new QWidget(this);
QVBoxLayout* layout = new QVBoxLayout(group);
layout->setContentsMargins(0, 0, 0, 0);
m_tableHandEye = new QTableWidget(this);
m_tableHandEye->setColumnCount(12);
m_tableHandEye->setHorizontalHeaderLabels({
"Cam\nX", "Cam\nY", "Cam\nZ",
"Cam\nRoll(rad)", "Cam\nPitch(rad)", "Cam\nYaw(rad)",
"Robot\nX", "Robot\nY", "Robot\nZ",
"Robot\nRoll(°)", "Robot\nPitch(°)", "Robot\nYaw(°)"
});
m_tableHandEye->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_tableHandEye->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);
m_tableHandEye->setSelectionBehavior(QAbstractItemView::SelectRows);
layout->addWidget(m_tableHandEye, 1);
// 内联按钮行
QHBoxLayout* btnLayout = new QHBoxLayout();
m_btnHandEyeAddRow = new QPushButton("添加行", this);
m_btnHandEyeDeleteRow = new QPushButton("删除行", this);
m_btnHandEyeCalib = new QPushButton("手眼标定", this);
m_btnHandEyeCalib->setStyleSheet(
"QPushButton { background-color: #4CAF50; color: white; font-weight: bold; padding: 4px 12px; }"
"QPushButton:hover { background-color: #45a049; }"
"QPushButton:pressed { background-color: #3d8b40; }"
);
connect(m_btnHandEyeAddRow, &QPushButton::clicked, this, [this]() {
int row = m_tableHandEye->rowCount();
m_tableHandEye->insertRow(row);
for (int col = 0; col < 12; ++col) {
m_tableHandEye->setItem(row, col, new QTableWidgetItem("0"));
}
m_tableHandEye->scrollToBottom();
});
connect(m_btnHandEyeDeleteRow, &QPushButton::clicked, this, [this]() {
int row = m_tableHandEye->currentRow();
if (row >= 0) {
m_tableHandEye->removeRow(row);
}
});
connect(m_btnHandEyeCalib, &QPushButton::clicked, this, [this]() {
int mode = m_cbCalibType->currentIndex();
if (mode == 0) {
emit requestEyeToHandCalib();
} else if (mode == 1) {
emit requestEyeInHandCalib();
}
});
btnLayout->addWidget(m_btnHandEyeAddRow);
btnLayout->addWidget(m_btnHandEyeDeleteRow);
btnLayout->addWidget(m_btnHandEyeCalib);
btnLayout->addStretch();
layout->addLayout(btnLayout);
// 数据输入区(水平布局:左侧输入框 + 右侧添加按钮)
QGroupBox* inputGroup = new QGroupBox("数据输入", group);
QHBoxLayout* inputMainLayout = new QHBoxLayout(inputGroup);
inputMainLayout->setContentsMargins(4, 4, 4, 4);
inputMainLayout->setSpacing(8);
// 左侧:输入框网格
QWidget* inputFields = new QWidget(this);
QGridLayout* inputLayout = new QGridLayout(inputFields);
inputLayout->setHorizontalSpacing(2);
inputLayout->setVerticalSpacing(4);
inputLayout->setContentsMargins(0, 0, 0, 0);
inputLayout->setColumnStretch(0, 0);
inputLayout->setColumnStretch(1, 1);
inputLayout->setColumnStretch(2, 0);
inputLayout->setColumnStretch(3, 1);
inputLayout->setColumnStretch(4, 0);
inputLayout->setColumnStretch(5, 1);
auto createSpinBox = [this]() {
QDoubleSpinBox* sb = new QDoubleSpinBox(this);
sb->setRange(-10000, 10000);
sb->setDecimals(3);
return sb;
};
// 第1行标定板 X/Y/Z
inputLayout->addWidget(new QLabel("标定板X(mm):", this), 0, 0);
m_inputCamX = createSpinBox();
inputLayout->addWidget(m_inputCamX, 0, 1);
inputLayout->addWidget(new QLabel("Y(mm):", this), 0, 2);
m_inputCamY = createSpinBox();
inputLayout->addWidget(m_inputCamY, 0, 3);
inputLayout->addWidget(new QLabel("Z(mm):", this), 0, 4);
m_inputCamZ = createSpinBox();
inputLayout->addWidget(m_inputCamZ, 0, 5);
// 第2行标定板 Rx/Ry/Rz (支持度/弧度切换)
m_lblCamRx = new QLabel("标定板Rx(rad):", this);
inputLayout->addWidget(m_lblCamRx, 1, 0);
m_inputCamRoll = createSpinBox();
inputLayout->addWidget(m_inputCamRoll, 1, 1);
m_lblCamRy = new QLabel("Ry(rad):", this);
inputLayout->addWidget(m_lblCamRy, 1, 2);
m_inputCamPitch = createSpinBox();
inputLayout->addWidget(m_inputCamPitch, 1, 3);
m_lblCamRz = new QLabel("Rz(rad):", this);
inputLayout->addWidget(m_lblCamRz, 1, 4);
m_inputCamYaw = createSpinBox();
inputLayout->addWidget(m_inputCamYaw, 1, 5);
// 第2.5行:角度单位选择
QLabel* lblAngleUnit = new QLabel("姿态输入单位:", this);
inputLayout->addWidget(lblAngleUnit, 2, 0);
m_cbCamAngleUnit = new QComboBox(this);
m_cbCamAngleUnit->addItem("弧度 (rad)");
m_cbCamAngleUnit->addItem("角度 (°)");
connect(m_cbCamAngleUnit, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this](int index) {
QString unitSuffix = (index == 0) ? "rad" : "°";
m_lblCamRx->setText(QString("标定板Rx(%1):").arg(unitSuffix));
m_lblCamRy->setText(QString("Ry(%1):").arg(unitSuffix));
m_lblCamRz->setText(QString("Rz(%1):").arg(unitSuffix));
// 同步更新表格列头
updateTableHeaders();
});
inputLayout->addWidget(m_cbCamAngleUnit, 2, 1);
// 第3行机械臂 X/Y/Z
inputLayout->addWidget(new QLabel("机械臂X(mm):", this), 3, 0);
m_inputRobotX = createSpinBox();
inputLayout->addWidget(m_inputRobotX, 3, 1);
inputLayout->addWidget(new QLabel("Y(mm):", this), 3, 2);
m_inputRobotY = createSpinBox();
inputLayout->addWidget(m_inputRobotY, 3, 3);
inputLayout->addWidget(new QLabel("Z(mm):", this), 3, 4);
m_inputRobotZ = createSpinBox();
inputLayout->addWidget(m_inputRobotZ, 3, 5);
// 第4行机械臂 Rx/Ry/Rz (角度)
inputLayout->addWidget(new QLabel("机械臂Rx(°):", this), 4, 0);
m_inputRobotRoll = createSpinBox();
inputLayout->addWidget(m_inputRobotRoll, 4, 1);
inputLayout->addWidget(new QLabel("Ry(°):", this), 4, 2);
m_inputRobotPitch = createSpinBox();
inputLayout->addWidget(m_inputRobotPitch, 4, 3);
inputLayout->addWidget(new QLabel("Rz(°):", this), 4, 4);
m_inputRobotYaw = createSpinBox();
inputLayout->addWidget(m_inputRobotYaw, 4, 5);
// 第5行不再放按钮
m_btnHandEyeAddInput = new QPushButton("添加到\n表格", this);
m_btnHandEyeAddInput->setMinimumHeight(60);
connect(m_btnHandEyeAddInput, &QPushButton::clicked, this, [this]() {
int row = m_tableHandEye->rowCount();
m_tableHandEye->insertRow(row);
m_tableHandEye->setItem(row, 0, new QTableWidgetItem(QString::number(m_inputCamX->value(), 'f', 3)));
m_tableHandEye->setItem(row, 1, new QTableWidgetItem(QString::number(m_inputCamY->value(), 'f', 3)));
m_tableHandEye->setItem(row, 2, new QTableWidgetItem(QString::number(m_inputCamZ->value(), 'f', 3)));
// 标定板姿态:直接存储用户输入的原始值(度存度、弧度存弧度)
m_tableHandEye->setItem(row, 3, new QTableWidgetItem(QString::number(m_inputCamRoll->value(), 'f', 3)));
m_tableHandEye->setItem(row, 4, new QTableWidgetItem(QString::number(m_inputCamPitch->value(), 'f', 3)));
m_tableHandEye->setItem(row, 5, new QTableWidgetItem(QString::number(m_inputCamYaw->value(), 'f', 3)));
m_tableHandEye->setItem(row, 6, new QTableWidgetItem(QString::number(m_inputRobotX->value(), 'f', 3)));
m_tableHandEye->setItem(row, 7, new QTableWidgetItem(QString::number(m_inputRobotY->value(), 'f', 3)));
m_tableHandEye->setItem(row, 8, new QTableWidgetItem(QString::number(m_inputRobotZ->value(), 'f', 3)));
m_tableHandEye->setItem(row, 9, new QTableWidgetItem(QString::number(m_inputRobotRoll->value(), 'f', 3)));
m_tableHandEye->setItem(row, 10, new QTableWidgetItem(QString::number(m_inputRobotPitch->value(), 'f', 3)));
m_tableHandEye->setItem(row, 11, new QTableWidgetItem(QString::number(m_inputRobotYaw->value(), 'f', 3)));
m_tableHandEye->scrollToBottom();
});
// 组装:左侧输入框 + 右侧按钮
inputMainLayout->addWidget(inputFields, 1);
inputMainLayout->addWidget(m_btnHandEyeAddInput);
layout->addWidget(inputGroup);
return group;
}
void CalibDataWidget::onCalibTypeChanged(int index)
{
// 更新表格可见性
m_groupHandEye->setVisible(index == 0 || index == 1);
m_groupTCPCalib->setVisible(index == 2);
// 根据模式更新表格标题
updateTableHeaders();
if (index == 0) {
m_btnHandEyeCalib->setText("Eye-To-Hand 标定");
} else if (index == 1) {
m_btnHandEyeCalib->setText("Eye-In-Hand 标定");
}
// TCP 按钮
m_tcpAddRowBtn->setEnabled(index == 2);
m_tcpRemoveRowBtn->setEnabled(index == 2);
m_btnTCPCalib->setEnabled(index == 2);
// 发送标定类型改变信号
if (index == 0) {
emit calibTypeChanged(HECCalibrationType::EyeToHand);
} else if (index == 1) {
emit calibTypeChanged(HECCalibrationType::EyeInHand);
}
}
void CalibDataWidget::updateTableHeaders()
{
int mode = m_cbCalibType->currentIndex();
QString camAngleUnit = (m_cbCamAngleUnit->currentIndex() == 0) ? "rad" : "°";
if (mode == 0) {
// Eye-To-Hand: 标定板在前,机械臂在后
m_tableHandEye->setHorizontalHeaderLabels({
"Cam\nX", "Cam\nY", "Cam\nZ",
QString("Cam\nRoll(%1)").arg(camAngleUnit),
QString("Cam\nPitch(%1)").arg(camAngleUnit),
QString("Cam\nYaw(%1)").arg(camAngleUnit),
"Robot\nX", "Robot\nY", "Robot\nZ",
"Robot\nRoll(°)", "Robot\nPitch(°)", "Robot\nYaw(°)"
});
} else if (mode == 1) {
// Eye-In-Hand: 机械臂在前,标定板在后
m_tableHandEye->setHorizontalHeaderLabels({
"Robot\nX", "Robot\nY", "Robot\nZ",
"Robot\nRoll(°)", "Robot\nPitch(°)", "Robot\nYaw(°)",
"Cam\nX", "Cam\nY", "Cam\nZ",
QString("Cam\nRoll(%1)").arg(camAngleUnit),
QString("Cam\nPitch(%1)").arg(camAngleUnit),
QString("Cam\nYaw(%1)").arg(camAngleUnit)
});
}
}
void CalibDataWidget::getEyeToHandData(std::vector<HECPoint3D>& eyePoints,
std::vector<HECPoint3D>& robotPoints) const
{
eyePoints.clear();
robotPoints.clear();
int rowCount = m_tableHandEye->rowCount();
for (int row = 0; row < rowCount; ++row) {
HECPoint3D eyePoint;
eyePoint.x = m_tableHandEye->item(row, 0) ?
m_tableHandEye->item(row, 0)->text().toDouble() : 0;
eyePoint.y = m_tableHandEye->item(row, 1) ?
m_tableHandEye->item(row, 1)->text().toDouble() : 0;
eyePoint.z = m_tableHandEye->item(row, 2) ?
m_tableHandEye->item(row, 2)->text().toDouble() : 0;
HECPoint3D robotPoint;
robotPoint.x = m_tableHandEye->item(row, 6) ?
m_tableHandEye->item(row, 6)->text().toDouble() : 0;
robotPoint.y = m_tableHandEye->item(row, 7) ?
m_tableHandEye->item(row, 7)->text().toDouble() : 0;
robotPoint.z = m_tableHandEye->item(row, 8) ?
m_tableHandEye->item(row, 8)->text().toDouble() : 0;
eyePoints.push_back(eyePoint);
robotPoints.push_back(robotPoint);
}
}
void CalibDataWidget::getEyeInHandData(std::vector<HECEyeInHandData>& calibData) const
{
calibData.clear();
// 创建标定实例用于欧拉角转换
IHandEyeCalib* calib = CreateHandEyeCalibInstance();
if (!calib) {
return;
}
// 获取用户选择的欧拉角顺序
HECEulerOrder eulerOrder = getEulerOrder();
int rowCount = m_tableHandEye->rowCount();
for (int row = 0; row < rowCount; ++row) {
HECEyeInHandData data;
// 获取末端位姿Eye-In-Hand模式下Robot数据在前6列
double endX = m_tableHandEye->item(row, 0) ?
m_tableHandEye->item(row, 0)->text().toDouble() : 0;
double endY = m_tableHandEye->item(row, 1) ?
m_tableHandEye->item(row, 1)->text().toDouble() : 0;
double endZ = m_tableHandEye->item(row, 2) ?
m_tableHandEye->item(row, 2)->text().toDouble() : 0;
double endRoll = m_tableHandEye->item(row, 3) ?
m_tableHandEye->item(row, 3)->text().toDouble() : 0;
double endPitch = m_tableHandEye->item(row, 4) ?
m_tableHandEye->item(row, 4)->text().toDouble() : 0;
double endYaw = m_tableHandEye->item(row, 5) ?
m_tableHandEye->item(row, 5)->text().toDouble() : 0;
// 使用标定接口统一转换欧拉角到旋转矩阵
HECEulerAngles endAngles(endRoll, endPitch, endYaw);
HECRotationMatrix R_end;
calib->EulerToRotationMatrix(endAngles, eulerOrder, R_end);
HECTranslationVector T_end(endX, endY, endZ);
data.endPose = HECHomogeneousMatrix(R_end, T_end);
// 获取相机观测点Eye-In-Hand模式下Cam数据在后6列
data.targetInCamera.x = m_tableHandEye->item(row, 6) ?
m_tableHandEye->item(row, 6)->text().toDouble() : 0;
data.targetInCamera.y = m_tableHandEye->item(row, 7) ?
m_tableHandEye->item(row, 7)->text().toDouble() : 0;
data.targetInCamera.z = m_tableHandEye->item(row, 8) ?
m_tableHandEye->item(row, 8)->text().toDouble() : 0;
calibData.push_back(data);
}
DestroyHandEyeCalibInstance(calib);
}
void CalibDataWidget::getEyeToHandPoseData(std::vector<HECEyeToHandData>& calibData) const
{
calibData.clear();
// 创建标定实例用于欧拉角转换
IHandEyeCalib* calib = CreateHandEyeCalibInstance();
if (!calib) {
return;
}
// 获取用户选择的欧拉角顺序
HECEulerOrder eulerOrder = getEulerOrder();
int rowCount = m_tableHandEye->rowCount();
for (int row = 0; row < rowCount; ++row) {
HECEyeToHandData data;
// 获取末端位姿Eye-To-Hand模式下Robot数据在后6列
double endX = m_tableHandEye->item(row, 6) ?
m_tableHandEye->item(row, 6)->text().toDouble() : 0;
double endY = m_tableHandEye->item(row, 7) ?
m_tableHandEye->item(row, 7)->text().toDouble() : 0;
double endZ = m_tableHandEye->item(row, 8) ?
m_tableHandEye->item(row, 8)->text().toDouble() : 0;
// 机器人姿态是角度,需要转换为弧度
double endRoll = m_tableHandEye->item(row, 9) ?
m_tableHandEye->item(row, 9)->text().toDouble() * M_PI / 180.0 : 0;
double endPitch = m_tableHandEye->item(row, 10) ?
m_tableHandEye->item(row, 10)->text().toDouble() * M_PI / 180.0 : 0;
double endYaw = m_tableHandEye->item(row, 11) ?
m_tableHandEye->item(row, 11)->text().toDouble() * M_PI / 180.0 : 0;
// 末端位姿和标定板姿态统一使用相同的欧拉角顺序
HECEulerAngles endAngles(endRoll, endPitch, endYaw);
HECRotationMatrix R_end;
calib->EulerToRotationMatrix(endAngles, eulerOrder, R_end);
HECTranslationVector T_end(endX, endY, endZ);
data.endPose = HECHomogeneousMatrix(R_end, T_end);
// 获取标定板在相机坐标系的位置Eye-To-Hand模式下Cam数据在前6列
double boardX = m_tableHandEye->item(row, 0) ?
m_tableHandEye->item(row, 0)->text().toDouble() : 0;
double boardY = m_tableHandEye->item(row, 1) ?
m_tableHandEye->item(row, 1)->text().toDouble() : 0;
double boardZ = m_tableHandEye->item(row, 2) ?
m_tableHandEye->item(row, 2)->text().toDouble() : 0;
// 获取标定板在相机坐标系的姿态
// 表格中存储的是欧拉角,当前单位可能是弧度或角度
double boardRoll = m_tableHandEye->item(row, 3) ?
m_tableHandEye->item(row, 3)->text().toDouble() : 0;
double boardPitch = m_tableHandEye->item(row, 4) ?
m_tableHandEye->item(row, 4)->text().toDouble() : 0;
double boardYaw = m_tableHandEye->item(row, 5) ?
m_tableHandEye->item(row, 5)->text().toDouble() : 0;
// 如果当前单位是角度,转换为弧度
if (m_cbCamAngleUnit->currentIndex() == 1) {
boardRoll = boardRoll * M_PI / 180.0;
boardPitch = boardPitch * M_PI / 180.0;
boardYaw = boardYaw * M_PI / 180.0;
}
// 标定板姿态与机器人姿态统一使用当前选中的欧拉角顺序
HECEulerAngles boardAngles(boardRoll, boardPitch, boardYaw);
HECRotationMatrix R_board;
calib->EulerToRotationMatrix(boardAngles, eulerOrder, R_board);
HECTranslationVector T_board(boardX, boardY, boardZ);
data.boardInCamera = HECHomogeneousMatrix(R_board, T_board);
calibData.push_back(data);
}
DestroyHandEyeCalibInstance(calib);
}
HECCalibrationType CalibDataWidget::getCalibType() const
{
return m_cbCalibType->currentIndex() == 0 ?
HECCalibrationType::EyeToHand : HECCalibrationType::EyeInHand;
}
int CalibDataWidget::getCalibTypeIndex() const
{
return m_cbCalibType->currentIndex();
}
HECEulerOrder CalibDataWidget::getEulerOrder() const
{
switch (m_cbEulerOrder->currentIndex()) {
case 0: return HECEulerOrder::ZYX;
case 1: return HECEulerOrder::XYZ;
case 2: return HECEulerOrder::XZY;
case 3: return HECEulerOrder::YXZ;
case 4: return HECEulerOrder::YZX;
case 5: return HECEulerOrder::ZXY;
default: return HECEulerOrder::ZYX;
}
}
void CalibDataWidget::clearAll()
{
m_tableHandEye->setRowCount(0);
m_tableTCP->setRowCount(0);
}
QWidget* CalibDataWidget::createTCPCalibGroup()
{
QWidget* group = new QWidget(this);
QVBoxLayout* layout = new QVBoxLayout(group);
layout->setContentsMargins(0, 0, 0, 0);
QHBoxLayout* modeLayout = new QHBoxLayout();
modeLayout->addWidget(new QLabel("标定模式:", this));
m_tcpModeCombo = new QComboBox(this);
m_tcpModeCombo->addItem("位置标定 (3-DOF)");
m_tcpModeCombo->addItem("完整标定 (6-DOF)");
connect(m_tcpModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CalibDataWidget::onTCPModeChanged);
modeLayout->addWidget(m_tcpModeCombo);
modeLayout->addWidget(new QLabel("欧拉角顺序:", this));
m_tcpEulerOrderCombo = new QComboBox(this);
m_tcpEulerOrderCombo->addItem("XYZ", static_cast<int>(HECEulerOrder::XYZ));
m_tcpEulerOrderCombo->addItem("XZY", static_cast<int>(HECEulerOrder::XZY));
m_tcpEulerOrderCombo->addItem("YXZ", static_cast<int>(HECEulerOrder::YXZ));
m_tcpEulerOrderCombo->addItem("YZX", static_cast<int>(HECEulerOrder::YZX));
m_tcpEulerOrderCombo->addItem("ZXY", static_cast<int>(HECEulerOrder::ZXY));
m_tcpEulerOrderCombo->addItem("ZYX (常用)", static_cast<int>(HECEulerOrder::ZYX));
m_tcpEulerOrderCombo->setCurrentIndex(5);
modeLayout->addWidget(m_tcpEulerOrderCombo);
modeLayout->addStretch();
layout->addLayout(modeLayout);
m_tableTCP = new QTableWidget(this);
m_tableTCP->setColumnCount(6);
m_tableTCP->setHorizontalHeaderLabels({"X", "Y", "Z", "Roll(°)", "Pitch(°)", "Yaw(°)"});
m_tableTCP->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_tableTCP->setSelectionBehavior(QAbstractItemView::SelectRows);
layout->addWidget(m_tableTCP, 1);
QHBoxLayout* btnLayout = new QHBoxLayout();
m_tcpAddRowBtn = new QPushButton("添加行", this);
m_tcpRemoveRowBtn = new QPushButton("删除行", this);
m_btnTCPCalib = new QPushButton("TCP 标定", this);
m_btnTCPCalib->setStyleSheet(
"QPushButton { background-color: #4CAF50; color: white; font-weight: bold; padding: 4px 12px; }"
"QPushButton:hover { background-color: #45a049; }"
"QPushButton:pressed { background-color: #3d8b40; }"
);
connect(m_tcpAddRowBtn, &QPushButton::clicked, this, &CalibDataWidget::onTCPAddRow);
connect(m_tcpRemoveRowBtn, &QPushButton::clicked, this, &CalibDataWidget::onTCPRemoveRow);
connect(m_btnTCPCalib, &QPushButton::clicked, this, &CalibDataWidget::requestTCPCalib);
btnLayout->addWidget(m_tcpAddRowBtn);
btnLayout->addWidget(m_tcpRemoveRowBtn);
btnLayout->addWidget(m_btnTCPCalib);
btnLayout->addStretch();
layout->addLayout(btnLayout);
QGroupBox* inputGroup = new QGroupBox("数据输入", group);
QHBoxLayout* tcpInputMainLayout = new QHBoxLayout(inputGroup);
tcpInputMainLayout->setContentsMargins(4, 4, 4, 4);
tcpInputMainLayout->setSpacing(8);
QWidget* tcpInputFields = new QWidget(this);
QGridLayout* inputLayout = new QGridLayout(tcpInputFields);
inputLayout->setHorizontalSpacing(2);
inputLayout->setVerticalSpacing(4);
inputLayout->setContentsMargins(0, 0, 0, 0);
inputLayout->setColumnStretch(0, 0);
inputLayout->setColumnStretch(1, 1);
inputLayout->setColumnStretch(2, 0);
inputLayout->setColumnStretch(3, 1);
inputLayout->setColumnStretch(4, 0);
inputLayout->setColumnStretch(5, 1);
auto createSpinBox = [this]() {
QDoubleSpinBox* sb = new QDoubleSpinBox(this);
sb->setRange(-10000, 10000);
sb->setDecimals(3);
return sb;
};
inputLayout->addWidget(new QLabel("X:", this), 0, 0);
m_inputTcpX = createSpinBox();
inputLayout->addWidget(m_inputTcpX, 0, 1);
inputLayout->addWidget(new QLabel("Y:", this), 0, 2);
m_inputTcpY = createSpinBox();
inputLayout->addWidget(m_inputTcpY, 0, 3);
inputLayout->addWidget(new QLabel("Z:", this), 0, 4);
m_inputTcpZ = createSpinBox();
inputLayout->addWidget(m_inputTcpZ, 0, 5);
inputLayout->addWidget(new QLabel("Roll(°):", this), 1, 0);
m_inputTcpRx = createSpinBox();
inputLayout->addWidget(m_inputTcpRx, 1, 1);
inputLayout->addWidget(new QLabel("Pitch(°):", this), 1, 2);
m_inputTcpRy = createSpinBox();
inputLayout->addWidget(m_inputTcpRy, 1, 3);
inputLayout->addWidget(new QLabel("Yaw(°):", this), 1, 4);
m_inputTcpRz = createSpinBox();
inputLayout->addWidget(m_inputTcpRz, 1, 5);
m_btnTcpAddInput = new QPushButton("添加到\n表格", this);
m_btnTcpAddInput->setMinimumHeight(40);
connect(m_btnTcpAddInput, &QPushButton::clicked, this, [this]() {
int row = m_tableTCP->rowCount();
m_tableTCP->insertRow(row);
m_tableTCP->setItem(row, 0, new QTableWidgetItem(QString::number(m_inputTcpX->value(), 'f', 3)));
m_tableTCP->setItem(row, 1, new QTableWidgetItem(QString::number(m_inputTcpY->value(), 'f', 3)));
m_tableTCP->setItem(row, 2, new QTableWidgetItem(QString::number(m_inputTcpZ->value(), 'f', 3)));
m_tableTCP->setItem(row, 3, new QTableWidgetItem(QString::number(m_inputTcpRx->value(), 'f', 3)));
m_tableTCP->setItem(row, 4, new QTableWidgetItem(QString::number(m_inputTcpRy->value(), 'f', 3)));
m_tableTCP->setItem(row, 5, new QTableWidgetItem(QString::number(m_inputTcpRz->value(), 'f', 3)));
m_tableTCP->scrollToBottom();
});
// 组装:左侧输入框 + 右侧按钮
tcpInputMainLayout->addWidget(tcpInputFields, 1);
tcpInputMainLayout->addWidget(m_btnTcpAddInput);
layout->addWidget(inputGroup);
m_tcpOrientationGroup = new QGroupBox("6-DOF 参数", group);
QGridLayout* oriLayout = new QGridLayout(m_tcpOrientationGroup);
oriLayout->addWidget(new QLabel("参考位姿索引:", this), 0, 0);
m_tcpRefPoseIndex = new QSpinBox(this);
m_tcpRefPoseIndex->setRange(0, 999);
oriLayout->addWidget(m_tcpRefPoseIndex, 0, 1);
oriLayout->addWidget(new QLabel("期望世界朝向 Rx(°):", this), 1, 0);
m_tcpWorldRx = new QDoubleSpinBox(this);
m_tcpWorldRx->setRange(-360, 360);
m_tcpWorldRx->setDecimals(2);
oriLayout->addWidget(m_tcpWorldRx, 1, 1);
oriLayout->addWidget(new QLabel("Ry(°):", this), 1, 2);
m_tcpWorldRy = new QDoubleSpinBox(this);
m_tcpWorldRy->setRange(-360, 360);
m_tcpWorldRy->setDecimals(2);
oriLayout->addWidget(m_tcpWorldRy, 1, 3);
oriLayout->addWidget(new QLabel("Rz(°):", this), 1, 4);
m_tcpWorldRz = new QDoubleSpinBox(this);
m_tcpWorldRz->setRange(-360, 360);
m_tcpWorldRz->setDecimals(2);
oriLayout->addWidget(m_tcpWorldRz, 1, 5);
m_tcpOrientationGroup->setVisible(false);
layout->addWidget(m_tcpOrientationGroup);
return group;
}
void CalibDataWidget::onTCPModeChanged(int index)
{
m_tcpOrientationGroup->setVisible(index == 1);
}
void CalibDataWidget::onTCPAddRow()
{
int row = m_tableTCP->rowCount();
m_tableTCP->insertRow(row);
for (int col = 0; col < 6; ++col) {
m_tableTCP->setItem(row, col, new QTableWidgetItem("0"));
}
m_tableTCP->scrollToBottom();
}
void CalibDataWidget::onTCPRemoveRow()
{
int row = m_tableTCP->currentRow();
if (row >= 0) {
m_tableTCP->removeRow(row);
}
}
HECTCPCalibData CalibDataWidget::getTCPCalibData() const
{
HECTCPCalibData data;
data.mode = (m_tcpModeCombo->currentIndex() == 0) ?
HECTCPCalibMode::PositionOnly : HECTCPCalibMode::Full6DOF;
HECEulerOrder eulerOrder = static_cast<HECEulerOrder>(
m_tcpEulerOrderCombo->currentData().toInt());
for (int row = 0; row < m_tableTCP->rowCount(); ++row) {
HECTCPCalibPose pose;
pose.x = m_tableTCP->item(row, 0) ? m_tableTCP->item(row, 0)->text().toDouble() : 0;
pose.y = m_tableTCP->item(row, 1) ? m_tableTCP->item(row, 1)->text().toDouble() : 0;
pose.z = m_tableTCP->item(row, 2) ? m_tableTCP->item(row, 2)->text().toDouble() : 0;
pose.rx = m_tableTCP->item(row, 3) ? m_tableTCP->item(row, 3)->text().toDouble() : 0;
pose.ry = m_tableTCP->item(row, 4) ? m_tableTCP->item(row, 4)->text().toDouble() : 0;
pose.rz = m_tableTCP->item(row, 5) ? m_tableTCP->item(row, 5)->text().toDouble() : 0;
pose.eulerOrder = eulerOrder;
data.poses.push_back(pose);
}
data.referencePoseIndex = m_tcpRefPoseIndex->value();
data.worldRx = m_tcpWorldRx->value();
data.worldRy = m_tcpWorldRy->value();
data.worldRz = m_tcpWorldRz->value();
data.worldEulerOrder = eulerOrder;
return data;
}
void CalibDataWidget::setRobotInput(double x, double y, double z,
double rx, double ry, double rz)
{
int mode = m_cbCalibType->currentIndex();
if (mode == 0) {
m_inputRobotX->setValue(x);
m_inputRobotY->setValue(y);
m_inputRobotZ->setValue(z);
m_inputRobotRoll->setValue(rx);
m_inputRobotPitch->setValue(ry);
m_inputRobotYaw->setValue(rz);
} else if (mode == 1) {
m_inputRobotX->setValue(x);
m_inputRobotY->setValue(y);
m_inputRobotZ->setValue(z);
m_inputRobotRoll->setValue(rx);
m_inputRobotPitch->setValue(ry);
m_inputRobotYaw->setValue(rz);
} else if (mode == 2) {
m_inputTcpX->setValue(x);
m_inputTcpY->setValue(y);
m_inputTcpZ->setValue(z);
m_inputTcpRx->setValue(rx);
m_inputTcpRy->setValue(ry);
m_inputTcpRz->setValue(rz);
}
}
void CalibDataWidget::setCameraInput(double x, double y, double z,
double rx, double ry, double rz)
{
m_inputCamX->setValue(x);
m_inputCamY->setValue(y);
m_inputCamZ->setValue(z);
// VrEyeView 回填的是欧拉角“度”UI 根据当前输入单位决定如何显示
if (m_cbCamAngleUnit->currentIndex() == 1) {
m_inputCamRoll->setValue(rx);
m_inputCamPitch->setValue(ry);
m_inputCamYaw->setValue(rz);
} else {
m_inputCamRoll->setValue(rx * M_PI / 180.0);
m_inputCamPitch->setValue(ry * M_PI / 180.0);
m_inputCamYaw->setValue(rz * M_PI / 180.0);
}
}
void CalibDataWidget::saveCalibData(const QString& filePath) const
{
QSettings ini(filePath, QSettings::IniFormat);
ini.setIniCodec("UTF-8");
int mode = m_cbCalibType->currentIndex();
const int eulerOrderIndex = m_cbEulerOrder->currentIndex();
QString axisOrder = "RzRyRx";
switch (eulerOrderIndex) {
case 1: axisOrder = "RxRyRz"; break;
case 2: axisOrder = "RxRzRy"; break;
case 3: axisOrder = "RyRxRz"; break;
case 4: axisOrder = "RyRzRx"; break;
case 5: axisOrder = "RzRxRy"; break;
case 0:
default:
axisOrder = "RzRyRx";
break;
}
ini.beginGroup("CommInfo");
ini.setValue("eCalibType", mode);
ini.setValue("sCalibTime", QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"));
ini.setValue("eCamAngleUnit", m_cbCamAngleUnit->currentIndex()); // 0=弧度, 1=角度
ini.setValue("eEulerOrder", eulerOrderIndex);
ini.setValue("eRobotPosAxisOrder", axisOrder);
if (mode == 0) {
int count = m_tableHandEye->rowCount();
ini.setValue("nPointCount", count);
ini.endGroup();
for (int row = 0; row < count; ++row) {
ini.beginGroup(QString("CalibPointInfo_%1").arg(row));
ini.setValue("dCamX", m_tableHandEye->item(row, 0) ? m_tableHandEye->item(row, 0)->text() : "0");
ini.setValue("dCamY", m_tableHandEye->item(row, 1) ? m_tableHandEye->item(row, 1)->text() : "0");
ini.setValue("dCamZ", m_tableHandEye->item(row, 2) ? m_tableHandEye->item(row, 2)->text() : "0");
ini.setValue("dCamRoll", m_tableHandEye->item(row, 3) ? m_tableHandEye->item(row, 3)->text() : "0");
ini.setValue("dCamPitch", m_tableHandEye->item(row, 4) ? m_tableHandEye->item(row, 4)->text() : "0");
ini.setValue("dCamYaw", m_tableHandEye->item(row, 5) ? m_tableHandEye->item(row, 5)->text() : "0");
ini.setValue("dRobotX", m_tableHandEye->item(row, 6) ? m_tableHandEye->item(row, 6)->text() : "0");
ini.setValue("dRobotY", m_tableHandEye->item(row, 7) ? m_tableHandEye->item(row, 7)->text() : "0");
ini.setValue("dRobotZ", m_tableHandEye->item(row, 8) ? m_tableHandEye->item(row, 8)->text() : "0");
ini.setValue("dRobotRoll", m_tableHandEye->item(row, 9) ? m_tableHandEye->item(row, 9)->text() : "0");
ini.setValue("dRobotPitch", m_tableHandEye->item(row, 10) ? m_tableHandEye->item(row, 10)->text() : "0");
ini.setValue("dRobotYaw", m_tableHandEye->item(row, 11) ? m_tableHandEye->item(row, 11)->text() : "0");
ini.endGroup();
}
} else if (mode == 1) {
int count = m_tableHandEye->rowCount();
ini.setValue("nPointCount", count);
ini.endGroup();
for (int row = 0; row < count; ++row) {
ini.beginGroup(QString("CalibPointInfo_%1").arg(row));
ini.setValue("dEndX", m_tableHandEye->item(row, 0) ? m_tableHandEye->item(row, 0)->text() : "0");
ini.setValue("dEndY", m_tableHandEye->item(row, 1) ? m_tableHandEye->item(row, 1)->text() : "0");
ini.setValue("dEndZ", m_tableHandEye->item(row, 2) ? m_tableHandEye->item(row, 2)->text() : "0");
ini.setValue("dEndRoll", m_tableHandEye->item(row, 3) ? m_tableHandEye->item(row, 3)->text() : "0");
ini.setValue("dEndPitch", m_tableHandEye->item(row, 4) ? m_tableHandEye->item(row, 4)->text() : "0");
ini.setValue("dEndYaw", m_tableHandEye->item(row, 5) ? m_tableHandEye->item(row, 5)->text() : "0");
ini.setValue("dCamX", m_tableHandEye->item(row, 6) ? m_tableHandEye->item(row, 6)->text() : "0");
ini.setValue("dCamY", m_tableHandEye->item(row, 7) ? m_tableHandEye->item(row, 7)->text() : "0");
ini.setValue("dCamZ", m_tableHandEye->item(row, 8) ? m_tableHandEye->item(row, 8)->text() : "0");
ini.setValue("dCamRoll", m_tableHandEye->item(row, 9) ? m_tableHandEye->item(row, 9)->text() : "0");
ini.setValue("dCamPitch", m_tableHandEye->item(row, 10) ? m_tableHandEye->item(row, 10)->text() : "0");
ini.setValue("dCamYaw", m_tableHandEye->item(row, 11) ? m_tableHandEye->item(row, 11)->text() : "0");
ini.endGroup();
}
} else {
int count = m_tableTCP->rowCount();
ini.setValue("nPoseCount", count);
ini.setValue("eCalibMode", m_tcpModeCombo->currentIndex());
ini.setValue("eEulerOrder", m_tcpEulerOrderCombo->currentIndex());
ini.setValue("nRefPoseIndex", m_tcpRefPoseIndex->value());
ini.setValue("dWorldRx", m_tcpWorldRx->value());
ini.setValue("dWorldRy", m_tcpWorldRy->value());
ini.setValue("dWorldRz", m_tcpWorldRz->value());
ini.endGroup();
for (int row = 0; row < count; ++row) {
ini.beginGroup(QString("CalibPoseInfo_%1").arg(row));
ini.setValue("dX", m_tableTCP->item(row, 0) ? m_tableTCP->item(row, 0)->text() : "0");
ini.setValue("dY", m_tableTCP->item(row, 1) ? m_tableTCP->item(row, 1)->text() : "0");
ini.setValue("dZ", m_tableTCP->item(row, 2) ? m_tableTCP->item(row, 2)->text() : "0");
ini.setValue("dRx", m_tableTCP->item(row, 3) ? m_tableTCP->item(row, 3)->text() : "0");
ini.setValue("dRy", m_tableTCP->item(row, 4) ? m_tableTCP->item(row, 4)->text() : "0");
ini.setValue("dRz", m_tableTCP->item(row, 5) ? m_tableTCP->item(row, 5)->text() : "0");
ini.endGroup();
}
}
}
void CalibDataWidget::loadCalibData(const QString& filePath)
{
QSettings ini(filePath, QSettings::IniFormat);
ini.setIniCodec("UTF-8");
ini.beginGroup("CommInfo");
int calibType = ini.value("eCalibType", -1).toInt();
// 读取标定板角度单位 (0=弧度, 1=角度默认0兼容旧文件)
int camAngleUnit = ini.value("eCamAngleUnit", 0).toInt();
m_cbCamAngleUnit->setCurrentIndex(camAngleUnit);
// 读取欧拉角顺序:优先使用当前工具保存的 eEulerOrder兼容旧文件的 eRobotPosAxisOrder
int savedEulerOrder = ini.value("eEulerOrder", -1).toInt();
if (savedEulerOrder >= 0 && savedEulerOrder <= 5) {
m_cbEulerOrder->setCurrentIndex(savedEulerOrder);
} else {
QString axisOrder = ini.value("eRobotPosAxisOrder", "RzRyRx").toString();
// 映射到UI的欧拉角顺序选择
if (axisOrder == "RxRyRz") {
m_cbEulerOrder->setCurrentIndex(1); // XYZ
} else if (axisOrder == "RxRzRy") {
m_cbEulerOrder->setCurrentIndex(2); // XZY
} else if (axisOrder == "RyRxRz") {
m_cbEulerOrder->setCurrentIndex(3); // YXZ
} else if (axisOrder == "RyRzRx") {
m_cbEulerOrder->setCurrentIndex(4); // YZX
} else if (axisOrder == "RzRxRy") {
m_cbEulerOrder->setCurrentIndex(5); // ZXY
} else {
m_cbEulerOrder->setCurrentIndex(0); // ZYX / RzRyRx
}
}
if (calibType == 0) {
int count = ini.value("nPointCount", 0).toInt();
int itemCount = ini.value("nCalibItemNum", 0).toInt();
ini.endGroup();
m_cbCalibType->setCurrentIndex(0);
if (itemCount > 0) {
m_tableHandEye->setRowCount(0);
m_boardPoseData.clear();
for (int i = 0; i < itemCount; ++i) {
ini.beginGroup(QString("pCalibItemList_%1").arg(i));
int row = m_tableHandEye->rowCount();
m_tableHandEye->insertRow(row);
m_tableHandEye->setItem(row, 0, new QTableWidgetItem(ini.value("dExtrinsic_0", "0").toString()));
m_tableHandEye->setItem(row, 1, new QTableWidgetItem(ini.value("dExtrinsic_1", "0").toString()));
m_tableHandEye->setItem(row, 2, new QTableWidgetItem(ini.value("dExtrinsic_2", "0").toString()));
double camRoll = ini.value("dExtrinsic_3", 0).toDouble();
double camPitch = ini.value("dExtrinsic_4", 0).toDouble();
double camYaw = ini.value("dExtrinsic_5", 0).toDouble();
m_tableHandEye->setItem(row, 3, new QTableWidgetItem(QString::number(camRoll, 'f', 6)));
m_tableHandEye->setItem(row, 4, new QTableWidgetItem(QString::number(camPitch, 'f', 6)));
m_tableHandEye->setItem(row, 5, new QTableWidgetItem(QString::number(camYaw, 'f', 6)));
m_tableHandEye->setItem(row, 6, new QTableWidgetItem(ini.value("sRobotPos_x", "0").toString()));
m_tableHandEye->setItem(row, 7, new QTableWidgetItem(ini.value("sRobotPos_y", "0").toString()));
m_tableHandEye->setItem(row, 8, new QTableWidgetItem(ini.value("sRobotPos_z", "0").toString()));
// 机器人姿态保持角度(不转换)
double robotRoll = ini.value("sRobotPos_roll", 0).toDouble();
double robotPitch = ini.value("sRobotPos_pitch", 0).toDouble();
double robotYaw = ini.value("sRobotPos_yaw", 0).toDouble();
m_tableHandEye->setItem(row, 9, new QTableWidgetItem(QString::number(robotRoll, 'f', 6)));
m_tableHandEye->setItem(row, 10, new QTableWidgetItem(QString::number(robotPitch, 'f', 6)));
m_tableHandEye->setItem(row, 11, new QTableWidgetItem(QString::number(robotYaw, 'f', 6)));
m_boardPoseData.push_back({camRoll, camPitch, camYaw});
ini.endGroup();
}
} else if (count > 0) {
m_tableHandEye->setRowCount(0);
for (int i = 0; i < count; ++i) {
ini.beginGroup(QString("CalibPointInfo_%1").arg(i));
int row = m_tableHandEye->rowCount();
m_tableHandEye->insertRow(row);
m_tableHandEye->setItem(row, 0, new QTableWidgetItem(ini.value("dCamX", "0").toString()));
m_tableHandEye->setItem(row, 1, new QTableWidgetItem(ini.value("dCamY", "0").toString()));
m_tableHandEye->setItem(row, 2, new QTableWidgetItem(ini.value("dCamZ", "0").toString()));
m_tableHandEye->setItem(row, 3, new QTableWidgetItem(ini.value("dCamRoll", "0").toString()));
m_tableHandEye->setItem(row, 4, new QTableWidgetItem(ini.value("dCamPitch", "0").toString()));
m_tableHandEye->setItem(row, 5, new QTableWidgetItem(ini.value("dCamYaw", "0").toString()));
m_tableHandEye->setItem(row, 6, new QTableWidgetItem(ini.value("dRobotX", "0").toString()));
m_tableHandEye->setItem(row, 7, new QTableWidgetItem(ini.value("dRobotY", "0").toString()));
m_tableHandEye->setItem(row, 8, new QTableWidgetItem(ini.value("dRobotZ", "0").toString()));
m_tableHandEye->setItem(row, 9, new QTableWidgetItem(ini.value("dRobotRoll", "0").toString()));
m_tableHandEye->setItem(row, 10, new QTableWidgetItem(ini.value("dRobotPitch", "0").toString()));
m_tableHandEye->setItem(row, 11, new QTableWidgetItem(ini.value("dRobotYaw", "0").toString()));
ini.endGroup();
}
}
} else if (calibType == 1) {
int count = ini.value("nPointCount", 0).toInt();
ini.endGroup();
m_cbCalibType->setCurrentIndex(1);
m_tableHandEye->setRowCount(0);
for (int i = 0; i < count; ++i) {
ini.beginGroup(QString("CalibPointInfo_%1").arg(i));
int row = m_tableHandEye->rowCount();
m_tableHandEye->insertRow(row);
m_tableHandEye->setItem(row, 0, new QTableWidgetItem(ini.value("dEndX", "0").toString()));
m_tableHandEye->setItem(row, 1, new QTableWidgetItem(ini.value("dEndY", "0").toString()));
m_tableHandEye->setItem(row, 2, new QTableWidgetItem(ini.value("dEndZ", "0").toString()));
m_tableHandEye->setItem(row, 3, new QTableWidgetItem(ini.value("dEndRoll", "0").toString()));
m_tableHandEye->setItem(row, 4, new QTableWidgetItem(ini.value("dEndPitch", "0").toString()));
m_tableHandEye->setItem(row, 5, new QTableWidgetItem(ini.value("dEndYaw", "0").toString()));
m_tableHandEye->setItem(row, 6, new QTableWidgetItem(ini.value("dCamX", "0").toString()));
m_tableHandEye->setItem(row, 7, new QTableWidgetItem(ini.value("dCamY", "0").toString()));
m_tableHandEye->setItem(row, 8, new QTableWidgetItem(ini.value("dCamZ", "0").toString()));
m_tableHandEye->setItem(row, 9, new QTableWidgetItem(ini.value("dCamRoll", "0").toString()));
m_tableHandEye->setItem(row, 10, new QTableWidgetItem(ini.value("dCamPitch", "0").toString()));
m_tableHandEye->setItem(row, 11, new QTableWidgetItem(ini.value("dCamYaw", "0").toString()));
ini.endGroup();
}
} else if (calibType == 2) {
int count = ini.value("nPoseCount", 0).toInt();
m_tcpModeCombo->setCurrentIndex(ini.value("eCalibMode", 0).toInt());
m_tcpEulerOrderCombo->setCurrentIndex(ini.value("eEulerOrder", 5).toInt());
m_tcpRefPoseIndex->setValue(ini.value("nRefPoseIndex", 0).toInt());
m_tcpWorldRx->setValue(ini.value("dWorldRx", 0).toDouble());
m_tcpWorldRy->setValue(ini.value("dWorldRy", 0).toDouble());
m_tcpWorldRz->setValue(ini.value("dWorldRz", 0).toDouble());
ini.endGroup();
m_cbCalibType->setCurrentIndex(2);
m_tableTCP->setRowCount(0);
for (int i = 0; i < count; ++i) {
ini.beginGroup(QString("CalibPoseInfo_%1").arg(i));
int row = m_tableTCP->rowCount();
m_tableTCP->insertRow(row);
m_tableTCP->setItem(row, 0, new QTableWidgetItem(ini.value("dX", "0").toString()));
m_tableTCP->setItem(row, 1, new QTableWidgetItem(ini.value("dY", "0").toString()));
m_tableTCP->setItem(row, 2, new QTableWidgetItem(ini.value("dZ", "0").toString()));
m_tableTCP->setItem(row, 3, new QTableWidgetItem(ini.value("dRx", "0").toString()));
m_tableTCP->setItem(row, 4, new QTableWidgetItem(ini.value("dRy", "0").toString()));
m_tableTCP->setItem(row, 5, new QTableWidgetItem(ini.value("dRz", "0").toString()));
ini.endGroup();
}
} else {
ini.endGroup();
}
}