撕裂增加结果绘制
This commit is contained in:
parent
ef11044756
commit
716fd5089f
@ -99,8 +99,9 @@ struct BeltTearingResult {
|
||||
std::vector<TearingData> result; // 检测结果描述
|
||||
bool bResultVaild = false;
|
||||
double confidence = 0.0; // 置信度
|
||||
QString serverName; // 服务器名称
|
||||
QDateTime timestamp; // 时间戳
|
||||
QString serverName; // 服务器名称
|
||||
QString aliasName; // 服务器别名
|
||||
QDateTime timestamp; // 时间戳
|
||||
};
|
||||
|
||||
|
||||
@ -130,6 +131,9 @@ public:
|
||||
|
||||
// 错误信息回调
|
||||
virtual void OnErrorOccurred(const QString& errorMessage) = 0;
|
||||
|
||||
// 清空撕裂数据回调
|
||||
virtual void OnClearTearingData() = 0;
|
||||
};
|
||||
|
||||
// 声明Qt元类型,使这些结构体能够在信号槽中传递
|
||||
|
||||
@ -27,7 +27,7 @@ public:
|
||||
|
||||
void Init(); // 状态更新接口
|
||||
|
||||
QStringList getServerNames() const;
|
||||
QStringList getServerNames() {return m_serverInfos.keys();}
|
||||
QString getServerIp(const QString &serverName) const ;
|
||||
quint16 getServerPort(const QString &serverName) const ;
|
||||
QString getServerDisplayName(const QString &serverName) const ;
|
||||
@ -44,14 +44,17 @@ public:
|
||||
|
||||
// 处理服务器信息响应
|
||||
void handleServerInfoResponse(const QString& serverName, const QJsonObject& responseObj);
|
||||
|
||||
// 重新检测方法
|
||||
void ResetDetect(const QString& targetServerAlias);
|
||||
|
||||
private:
|
||||
// IBeltTearingPresenter interface implementation
|
||||
bool initializeConfig(const QString &configPath);
|
||||
bool connectToServer(const ServerInfo &serverInfo, const QString &serverName = QString());
|
||||
void disconnectFromServer(const QString &serverName = QString()) ;
|
||||
bool isConnected(const QString &serverName = QString()) const ;
|
||||
bool sendData(const QByteArray &data, const QString &serverName = QString());
|
||||
bool connectToServer(const ServerInfo &serverInfo, const QString &aliasName);
|
||||
void disconnectFromServer(const QString &aliasName = QString()) ;
|
||||
bool isConnected(const QString &aliasName = QString()) const ;
|
||||
bool sendData(const QByteArray &data, const QString &aliasName = QString());
|
||||
|
||||
|
||||
private slots:
|
||||
@ -65,8 +68,8 @@ private:
|
||||
// static void tcpLinkStatusCallback(bool connected);
|
||||
|
||||
// 实例方法
|
||||
void handleTcpDataReceived(const QString &serverName, const char* pData, const int nLen);
|
||||
void handleTcpLinkStatus(const QString &serverName, bool connected);
|
||||
void handleTcpDataReceived(const QString &aliasName, const char* pData, const int nLen);
|
||||
void handleTcpLinkStatus(const QString &aliasName, bool connected);
|
||||
|
||||
private:
|
||||
IVrBeltTearingConfig * m_config = nullptr; // 配置接口
|
||||
|
||||
@ -71,16 +71,17 @@ bool BeltTearingPresenter::initializeConfig(const QString &configPath)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取所有服务器配置
|
||||
const auto &servers = configResult.servers;
|
||||
if (servers.empty()) {
|
||||
if (configResult.servers.empty()) {
|
||||
LOG_WARNING("No servers configured");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 清空现有配置
|
||||
m_serverInfos.clear();
|
||||
|
||||
|
||||
// 获取所有服务器配置
|
||||
const auto &servers = configResult.servers;
|
||||
|
||||
// 存储所有启用的服务器信息
|
||||
QList<DeviceInfo> devices;
|
||||
QStringList deviceAliases;
|
||||
@ -102,22 +103,17 @@ bool BeltTearingPresenter::initializeConfig(const QString &configPath)
|
||||
}
|
||||
|
||||
// 连接到所有服务器
|
||||
for(size_t i = 0 ; i < devices.size() ; i++){
|
||||
for(size_t i = 0 ; i < servers.size() ; i++){
|
||||
connectToServer(servers[i], deviceAliases[i]);
|
||||
}
|
||||
|
||||
if (m_serverInfos.empty()) {
|
||||
LOG_WARNING("No enabled servers found\n");
|
||||
return false;
|
||||
}
|
||||
LOG_DEBUG("Config loaded successfully. Found %d enabled servers\n", m_serverInfos.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BeltTearingPresenter::connectToServer(const ServerInfo &serverInfo, const QString &serverName)
|
||||
bool BeltTearingPresenter::connectToServer(const ServerInfo &serverInfo, const QString &aliasName)
|
||||
{
|
||||
QString targetServerName = serverName;
|
||||
QString targetServerName = aliasName;
|
||||
|
||||
// 创建TCP客户端(如果不存在)
|
||||
if (!m_tcpClients.contains(targetServerName)) {
|
||||
@ -221,11 +217,6 @@ bool BeltTearingPresenter::sendData(const QByteArray &data, const QString &serve
|
||||
return success;
|
||||
}
|
||||
|
||||
QStringList BeltTearingPresenter::getServerNames() const
|
||||
{
|
||||
return m_serverInfos.keys();
|
||||
}
|
||||
|
||||
QString BeltTearingPresenter::getServerIp(const QString &serverName) const
|
||||
{
|
||||
if (m_serverInfos.contains(serverName)) {
|
||||
@ -282,15 +273,15 @@ void BeltTearingPresenter::onTcpError(const QString &serverName, const QString &
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, const char* pData, const int nLen)
|
||||
void BeltTearingPresenter::handleTcpDataReceived(const QString &aliasName, const char* pData, const int nLen)
|
||||
{
|
||||
if (!pData || nLen <= 0) return;
|
||||
|
||||
// 将新数据添加到缓存
|
||||
m_dataBuffers[serverName].append(pData, nLen);
|
||||
m_dataBuffers[aliasName].append(pData, nLen);
|
||||
|
||||
// 检查是否有完整的数据包
|
||||
QByteArray &buffer = m_dataBuffers[serverName];
|
||||
QByteArray &buffer = m_dataBuffers[aliasName];
|
||||
const QByteArray endMarker = "___END___\r\n";
|
||||
|
||||
int endPos = buffer.indexOf(endMarker);
|
||||
@ -300,7 +291,7 @@ void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, cons
|
||||
// LOG_DEBUG("Found complete packet for %s: size=%d\n", serverName.toStdString().c_str(), completePacket.size());
|
||||
|
||||
// 处理完整数据包
|
||||
processCompletePacket(serverName, completePacket);
|
||||
processCompletePacket(aliasName, completePacket);
|
||||
|
||||
// 从缓存中移除已处理的数据(包括结束标记)
|
||||
buffer.remove(0, endPos + endMarker.length());
|
||||
@ -310,15 +301,15 @@ void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, cons
|
||||
}
|
||||
|
||||
// 如果缓存过大,清空以避免内存问题
|
||||
if (buffer.size() > 1024 * 1024) { // 1MB 限制
|
||||
LOG_WARNING("Buffer too large for %s, clearing buffer\n", serverName.toStdString().c_str());
|
||||
if (buffer.size() > 1024 * 1024 * 2) { // 2MB 限制
|
||||
LOG_WARNING("Buffer too large for %s, clearing buffer\n", aliasName.toStdString().c_str());
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::processCompletePacket(const QString &serverName, const QByteArray &completeData)
|
||||
void BeltTearingPresenter::processCompletePacket(const QString &aliasName, const QByteArray &completeData)
|
||||
{
|
||||
// LOG_DEBUG("Processing complete packet from %s: size=%d\n", serverName.toStdString().c_str(), completeData.size());
|
||||
// LOG_DEBUG("Processing complete packet from %s: size=%d\n", aliasName.toStdString().c_str(), completeData.size());
|
||||
|
||||
// 解析数据包协议头
|
||||
if (completeData.size() < 5) {
|
||||
@ -397,7 +388,27 @@ void BeltTearingPresenter::processCompletePacket(const QString &serverName, cons
|
||||
// 检查是否是配置响应
|
||||
if (command == "configResponse") {
|
||||
// 处理配置响应数据
|
||||
emit serverDataReceived(serverName, jsonObj);
|
||||
emit serverDataReceived(aliasName, jsonObj);
|
||||
return;
|
||||
}
|
||||
// 检查是否是重新检测响应
|
||||
else if (command == "resetDetectResponse") {
|
||||
// 处理重新检测响应
|
||||
QString status = jsonObj["status"].toString();
|
||||
QString message = jsonObj["message"].toString();
|
||||
|
||||
LOG_INFO("Received reset detect response from server %s: status=%s, message=%s\n",
|
||||
aliasName.toStdString().c_str(),
|
||||
status.toStdString().c_str(),
|
||||
message.toStdString().c_str());
|
||||
|
||||
// 通过状态更新接口通知上层
|
||||
if (m_statusUpdate) {
|
||||
m_statusUpdate->OnStatusUpdate(QString("来自服务器 %1 的重新检测响应: %2").arg(aliasName).arg(message));
|
||||
// 清空撕裂数据表,避免残留数据
|
||||
m_statusUpdate->OnClearTearingData();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -412,8 +423,9 @@ void BeltTearingPresenter::processCompletePacket(const QString &serverName, cons
|
||||
|
||||
// 通知上层处理结果
|
||||
if (m_statusUpdate) {
|
||||
tearResult.serverName = serverName;
|
||||
tearResult.timestamp = QDateTime::currentDateTime();
|
||||
tearResult.serverName = QString::fromStdString(m_serverInfos[aliasName].name);
|
||||
tearResult.aliasName = aliasName;
|
||||
tearResult.timestamp = QDateTime::currentDateTime();
|
||||
|
||||
try {
|
||||
m_statusUpdate->OnTearingResult(tearResult);
|
||||
@ -425,34 +437,34 @@ void BeltTearingPresenter::processCompletePacket(const QString &serverName, cons
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::handleTcpLinkStatus(const QString &serverName, bool connected)
|
||||
void BeltTearingPresenter::handleTcpLinkStatus(const QString &aliasName, bool connected)
|
||||
{
|
||||
m_connectionStatus[serverName] = connected;
|
||||
m_connectionStatus[aliasName] = connected;
|
||||
|
||||
if (connected) {
|
||||
onConnected(serverName);
|
||||
onConnected(aliasName);
|
||||
} else {
|
||||
onDisconnected(serverName);
|
||||
onDisconnected(aliasName);
|
||||
}
|
||||
}
|
||||
|
||||
bool BeltTearingPresenter::sendParametersToServer(const ByteDataType dataType, const QString& serverName, const QByteArray& paramData)
|
||||
bool BeltTearingPresenter::sendParametersToServer(const ByteDataType dataType, const QString& aliasName, const QByteArray& paramData)
|
||||
{
|
||||
if (!m_serverInfos.contains(serverName)) {
|
||||
LOG_ERROR("Server not found: %s\n", serverName.toStdString().c_str());
|
||||
if (!m_serverInfos.contains(aliasName)) {
|
||||
LOG_ERROR("Server not found: %s\n", aliasName.toStdString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_connectionStatus.value(serverName, false)) {
|
||||
LOG_ERROR("Server not connected: %s\n", serverName.toStdString().c_str());
|
||||
if (!m_connectionStatus.value(aliasName, false)) {
|
||||
LOG_ERROR("Server not connected: %s\n", aliasName.toStdString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG("req : %s \n", serverName.toStdString().c_str());
|
||||
LOG_DEBUG("req : %s \n", aliasName.toStdString().c_str());
|
||||
|
||||
IVrTCPClient* tcpClient = m_tcpClients.value(serverName, nullptr);
|
||||
IVrTCPClient* tcpClient = m_tcpClients.value(aliasName, nullptr);
|
||||
if (!tcpClient) {
|
||||
LOG_ERROR("TCP client not found for server: %s\n", serverName.toStdString().c_str());
|
||||
LOG_ERROR("TCP client not found for server: %s\n", aliasName.toStdString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -476,9 +488,9 @@ bool BeltTearingPresenter::sendParametersToServer(const ByteDataType dataType, c
|
||||
// 发送数据
|
||||
bool success = tcpClient->SendData(packet.constData(), packet.size());
|
||||
if (success) {
|
||||
LOG_INFO("Algorithm parameters sent to server %s successfully\n", serverName.toStdString().c_str());
|
||||
LOG_INFO("Algorithm parameters sent to server %s successfully\n", aliasName.toStdString().c_str());
|
||||
} else {
|
||||
LOG_ERROR("Failed to send algorithm parameters to server %s\n", serverName.toStdString().c_str());
|
||||
LOG_ERROR("Failed to send algorithm parameters to server %s\n", aliasName.toStdString().c_str());
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -488,10 +500,6 @@ void BeltTearingPresenter::handleServerInfoResponse(const QString& serverName, c
|
||||
{
|
||||
LOG_INFO("Received server info response from %s\n", serverName.toStdString().c_str());
|
||||
|
||||
// 检查是否有DialogNetConfig实例需要接收这个数据
|
||||
// 这里可以通过信号槽机制来通知界面更新
|
||||
// 暂时只记录日志,实际实现中可能需要通过主窗口传递给DialogNetConfig
|
||||
|
||||
if (responseObj.contains("serverInfo")) {
|
||||
QJsonObject serverInfo = responseObj["serverInfo"].toObject();
|
||||
QString serverVersion = serverInfo["version"].toString();
|
||||
@ -517,3 +525,53 @@ void BeltTearingPresenter::handleServerInfoResponse(const QString& serverName, c
|
||||
emit serverDataReceived(serverName, responseObj);
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::ResetDetect(const QString& targetServerAlias)
|
||||
{
|
||||
LOG_INFO("Resetting detection for server: %s\n", targetServerAlias.toStdString().c_str());
|
||||
|
||||
// 检查目标服务端是否存在且已连接
|
||||
if (!m_serverInfos.contains(targetServerAlias)) {
|
||||
LOG_ERROR("Target server not found: %s\n", targetServerAlias.toStdString().c_str());
|
||||
if (m_statusUpdate) {
|
||||
m_statusUpdate->OnStatusUpdate(QString("未找到目标服务器: %1").arg(targetServerAlias));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isConnected(targetServerAlias)) {
|
||||
LOG_ERROR("Target server not connected: %s\n", targetServerAlias.toStdString().c_str());
|
||||
if (m_statusUpdate) {
|
||||
m_statusUpdate->OnStatusUpdate(QString("目标服务器未连接: %1").arg(targetServerAlias));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 通知UI清空数据
|
||||
if (m_statusUpdate) {
|
||||
m_statusUpdate->OnStatusUpdate(QString("正在重新检测服务器: %1...").arg(targetServerAlias));
|
||||
// 清空数据的操作应该由UI层处理
|
||||
}
|
||||
|
||||
// 向指定的服务端发送重新检测指令
|
||||
QJsonObject resetCommand;
|
||||
resetCommand["command"] = "resetDetect";
|
||||
resetCommand["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
|
||||
QJsonDocument doc(resetCommand);
|
||||
QByteArray commandData = doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
// 只向指定的服务器发送重新检测指令
|
||||
bool success = sendParametersToServer(ByteDataType::Text, targetServerAlias, commandData);
|
||||
if (success) {
|
||||
LOG_INFO("Reset detect command sent to server: %s\n", targetServerAlias.toStdString().c_str());
|
||||
if (m_statusUpdate) {
|
||||
m_statusUpdate->OnStatusUpdate(QString("重新检测指令已发送至服务器: %1").arg(targetServerAlias));
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("Failed to send reset detect command to server: %s\n", targetServerAlias.toStdString().c_str());
|
||||
if (m_statusUpdate) {
|
||||
m_statusUpdate->OnStatusUpdate(QString("发送重新检测指令失败: %1").arg(targetServerAlias));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#define VERSION_H
|
||||
|
||||
#define BELT_TEARING_APP_VERSION_STRING "2.0.1"
|
||||
#define BELT_TEARING_APP_VERSION_BUILD "4"
|
||||
#define BELT_TEARING_APP_VERSION_BUILD "5"
|
||||
#define BELT_TEARING_APP_PRODUCT_NAME "BeltTearingApp"
|
||||
#define BELT_TEARING_APP_COMPANY_NAME "VisionRobot"
|
||||
#define BELT_TEARING_APP_COPYRIGHT "Copyright (C) 2024 VisionRobot. All rights reserved."
|
||||
|
||||
@ -18,6 +18,7 @@ int main(int argc, char *argv[])
|
||||
qRegisterMetaType<QVector<int>>("QVector<int>");
|
||||
qRegisterMetaType<QList<QPersistentModelIndex>>("QList<QPersistentModelIndex>");
|
||||
qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>("QAbstractItemModel::LayoutChangeHint");
|
||||
qRegisterMetaType<Qt::SortOrder>("Qt::SortOrder");
|
||||
|
||||
// Register custom meta types for BeltTearing
|
||||
qRegisterMetaType<TearingData>("TearingData");
|
||||
|
||||
@ -26,6 +26,14 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
// 设置窗口图标
|
||||
this->setWindowIcon(QIcon(":/resource/logo.png"));
|
||||
|
||||
// 设置状态栏字体
|
||||
QFont statusFont = statusBar()->font();
|
||||
statusFont.setPointSize(12);
|
||||
statusBar()->setFont(statusFont);
|
||||
|
||||
// 设置状态栏颜色和padding
|
||||
statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }");
|
||||
|
||||
// 隐藏标题栏
|
||||
setWindowFlags(Qt::FramelessWindowHint);
|
||||
|
||||
@ -64,8 +72,10 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
m_presenter->setStatusUpdate(this);
|
||||
|
||||
// 连接服务器数据接收信号
|
||||
connect(m_presenter, &BeltTearingPresenter::serverDataReceived,
|
||||
this, &MainWindow::onServerDataReceived);
|
||||
connect(m_presenter, &BeltTearingPresenter::serverDataReceived, this, &MainWindow::onServerDataReceived);
|
||||
|
||||
// 连接设备点击信号到重新检测槽函数
|
||||
connect(m_deviceStatusWidget, &DeviceStatusWidget::deviceClicked, this, &MainWindow::onDeviceClicked);
|
||||
|
||||
// 设置版本信息显示
|
||||
setupVersionDisplay();
|
||||
@ -259,6 +269,52 @@ void MainWindow::onServerDataReceived(const QString& serverName, const QJsonObje
|
||||
statusBar()->showMessage("从服务器 " + serverName + " 获取参数完成");
|
||||
}
|
||||
|
||||
// 设备点击事件处理槽函数
|
||||
void MainWindow::onDeviceClicked(const QString& deviceAlias)
|
||||
{
|
||||
// 获取设备显示名称
|
||||
QString deviceName = deviceAlias;
|
||||
if (m_presenter) {
|
||||
deviceName = m_presenter->getServerDisplayName(deviceAlias);
|
||||
if (deviceName.isEmpty()) {
|
||||
deviceName = deviceAlias;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建自定义的确认对话框
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle("重新检测确认");
|
||||
msgBox.setText(QString("确定要对设备 \"%1\" 进行重新检测吗?").arg(deviceName));
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
|
||||
// 设置白色字体样式
|
||||
msgBox.setStyleSheet("QLabel { color: white; } QPushButton { color: white; }");
|
||||
|
||||
// 添加中文按钮
|
||||
QPushButton *yesButton = msgBox.addButton("是", QMessageBox::YesRole);
|
||||
QPushButton *noButton = msgBox.addButton("否", QMessageBox::NoRole);
|
||||
|
||||
// 显示对话框并获取用户选择
|
||||
msgBox.exec();
|
||||
|
||||
// 如果用户确认重新检测
|
||||
if (msgBox.clickedButton() == yesButton) {
|
||||
|
||||
// 调用Presenter的ResetDetect方法进行重新检测,传递设备别名
|
||||
if (m_presenter) {
|
||||
m_presenter->ResetDetect(deviceAlias);
|
||||
}
|
||||
|
||||
// 清空检测数据表格
|
||||
if (m_tearingDataTableWidget) {
|
||||
m_tearingDataTableWidget->clearData();
|
||||
}
|
||||
|
||||
// 更新状态栏信息
|
||||
statusBar()->showMessage(QString("已启动对设备 \"%1\" 的重新检测").arg(deviceName));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onConfigSaved()
|
||||
{
|
||||
// 重新初始化Presenter
|
||||
@ -296,8 +352,7 @@ void MainWindow::OnNeedShowImageCount(const QStringList &deviceAliases)
|
||||
for (const QString& alias : deviceAliases) {
|
||||
QString displayName = m_presenter->getServerDisplayName(alias);
|
||||
QString ip = m_presenter->getServerIp(alias);
|
||||
devices.append(DeviceInfo(displayName.isEmpty() ? alias : displayName,
|
||||
alias, ip, DeviceStatus::Offline, true));
|
||||
devices.append(DeviceInfo(displayName.isEmpty() ? alias : displayName, alias, ip, DeviceStatus::Offline, true));
|
||||
}
|
||||
m_deviceStatusWidget->setDevices(devices);
|
||||
}
|
||||
@ -309,10 +364,10 @@ void MainWindow::OnTearingResult(const BeltTearingResult &result)
|
||||
// 如果图像有效,显示在网格控件中
|
||||
if (result.bImageValid && !result.image.isNull()) {
|
||||
// 使用服务器名称作为别名
|
||||
m_gridView->setImages(result.serverName, result.image);
|
||||
m_gridView->setImages(result.aliasName, result.image);
|
||||
} else if (result.bResultVaild) {
|
||||
// 直接处理std::vector<TearingData>
|
||||
m_tearingDataTableWidget->addDataBatch(result.result);
|
||||
m_tearingDataTableWidget->addDataBatch(result.serverName, result.result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,6 +431,13 @@ void MainWindow::OnDeviceStatusChanged(const QString &deviceName, int deviceStat
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::OnClearTearingData()
|
||||
{
|
||||
if (m_tearingDataTableWidget) {
|
||||
m_tearingDataTableWidget->clearData();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setupVersionDisplay()
|
||||
{
|
||||
// 创建版本信息标签
|
||||
@ -396,7 +458,7 @@ void MainWindow::setupVersionDisplay()
|
||||
m_versionLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
|
||||
// 设置样式使其看起来更美观
|
||||
m_versionLabel->setStyleSheet("QLabel { color: #666666; font-size: 12px; margin-right: 10px; }");
|
||||
m_versionLabel->setStyleSheet("QLabel { color: rgb(239, 241, 245); font-size: 12px; margin-right: 10px; }");
|
||||
|
||||
// 将版本标签添加到状态栏的右侧
|
||||
statusBar()->addPermanentWidget(m_versionLabel);
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include <QStringList>
|
||||
#include <QSplitter>
|
||||
#include <QResizeEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include "models/ImageInfoModel.h"
|
||||
#include "widgets/ImageGridWithTableWidget.h"
|
||||
#include "widgets/ImageGridWidget.h"
|
||||
@ -39,6 +41,7 @@ public:
|
||||
void OnServerDisconnected(const QString& serverName) override;
|
||||
void OnWorkStatusChanged(BeltTearingWorkStatus status) override;
|
||||
void OnErrorOccurred(const QString& errorMessage) override;
|
||||
void OnClearTearingData() override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
@ -63,6 +66,8 @@ private slots:
|
||||
|
||||
void onServerDataReceived(const QString& serverName, const QJsonObject& data);
|
||||
|
||||
// 设备点击事件处理槽函数
|
||||
void onDeviceClicked(const QString& deviceAlias);
|
||||
private:
|
||||
|
||||
void resizeToFitContent();
|
||||
|
||||
@ -105,29 +105,32 @@ border: none;</string>
|
||||
<string/>
|
||||
</property>
|
||||
<widget class="QLabel" name="label_work">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>1470</x>
|
||||
<y>20</y>
|
||||
<width>271</width>
|
||||
<height>81</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>24</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>工作状态</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>1470</x>
|
||||
<y>20</y>
|
||||
<width>271</width>
|
||||
<height>81</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>24</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>工作状态</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btn_close">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
@ -183,6 +186,9 @@ background-color: rgba(255, 255, 255, 0);</string>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btn_stop">
|
||||
<property name="geometry">
|
||||
@ -205,6 +211,9 @@ background-color: rgba(255, 255, 255, 0);</string>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btn_algo_config">
|
||||
<property name="geometry">
|
||||
|
||||
@ -12,6 +12,18 @@ TearingDataTableWidget::TearingDataTableWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_tableWidget(nullptr)
|
||||
{
|
||||
// 初始化与服务端颜色协调的颜色数组
|
||||
m_tearColors[0] = QColor(255, 105, 97); // 珊瑚红
|
||||
m_tearColors[1] = QColor(255, 160, 122); // 浅鲑鱼色
|
||||
m_tearColors[2] = QColor(173, 216, 230); // 浅蓝色
|
||||
m_tearColors[3] = QColor(144, 238, 144); // 浅绿色
|
||||
m_tearColors[4] = QColor(255, 182, 193); // 浅粉色
|
||||
m_tearColors[5] = QColor(221, 160, 221); // 梅花色
|
||||
m_tearColors[6] = QColor(255, 215, 0); // 金色
|
||||
m_tearColors[7] = QColor(240, 128, 128); // 玫瑰色
|
||||
m_tearColors[8] = QColor(135, 206, 250); // 天蓝色
|
||||
m_tearColors[9] = QColor(127, 255, 212); // 碧绿色
|
||||
|
||||
setupUI();
|
||||
setupTable();
|
||||
}
|
||||
@ -36,7 +48,7 @@ void TearingDataTableWidget::setupTable()
|
||||
// 设置表头标签
|
||||
QStringList headers;
|
||||
// headers << "ID" << "等级" << "状态" << "类型" /*<< "起始行" << "结束行" */<< "深度" << "宽度" << "长度" << "老化";
|
||||
headers << "ID" << "状态" << "类型" << "深度(mm)" << "宽度(mm)" << "长度(mm)";
|
||||
headers << "设备" << "编号" << "状态" << "类型" << "深度(mm)" << "宽度(mm)" << "长度(mm)" << "时间";
|
||||
|
||||
// 设置表格属性
|
||||
m_tableWidget->setColumnCount(headers.size());
|
||||
@ -54,12 +66,14 @@ void TearingDataTableWidget::setupTable()
|
||||
m_tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
||||
|
||||
// 设置列宽
|
||||
m_tableWidget->setColumnWidth(0, 62); // ID列
|
||||
m_tableWidget->setColumnWidth(1, 100); // 状态列
|
||||
m_tableWidget->setColumnWidth(2, 80); // 类型列
|
||||
m_tableWidget->setColumnWidth(3, 100); // 深度列
|
||||
m_tableWidget->setColumnWidth(4, 100); // 宽度列
|
||||
m_tableWidget->setColumnWidth(5, 100); // 长度列
|
||||
m_tableWidget->setColumnWidth(0, 85); // 名称
|
||||
m_tableWidget->setColumnWidth(1, 62); // ID列
|
||||
m_tableWidget->setColumnWidth(2, 50); // 状态列
|
||||
m_tableWidget->setColumnWidth(3, 50); // 类型列
|
||||
m_tableWidget->setColumnWidth(4, 65); // 深度列
|
||||
m_tableWidget->setColumnWidth(5, 65); // 宽度列
|
||||
m_tableWidget->setColumnWidth(6, 65); // 长度列
|
||||
m_tableWidget->setColumnWidth(7, 100); // 时间列
|
||||
#endif
|
||||
// 设置样式表
|
||||
m_tableWidget->setStyleSheet(
|
||||
@ -81,45 +95,39 @@ void TearingDataTableWidget::setupTable()
|
||||
// 启用表格排序功能
|
||||
m_tableWidget->setSortingEnabled(true);
|
||||
|
||||
// 设置默认按ID列升序排序
|
||||
m_tableWidget->sortItems(0, Qt::AscendingOrder);
|
||||
// 设置默认按ID列倒序排序
|
||||
m_tableWidget->sortItems(1, Qt::DescendingOrder);
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::addData(const TearingData &data)
|
||||
{
|
||||
// 禁用排序以提高性能,批量处理后再启用
|
||||
m_tableWidget->setSortingEnabled(false);
|
||||
|
||||
// 查找是否已存在相同ID的行
|
||||
int existingRow = findExistingRowById(data.id);
|
||||
|
||||
int row;
|
||||
if (existingRow >= 0) {
|
||||
// 如果存在相同ID,更新该行
|
||||
row = existingRow;
|
||||
} else {
|
||||
// 如果不存在,插入新行
|
||||
row = m_tableWidget->rowCount();
|
||||
m_tableWidget->insertRow(row);
|
||||
}
|
||||
void TearingDataTableWidget::_AddDataToTable(const QString devName, const TearingData &data, int row)
|
||||
{
|
||||
QTableWidgetItem *nameItem = new QTableWidgetItem(devName);
|
||||
nameItem->setTextAlignment(Qt::AlignCenter);
|
||||
m_tableWidget->setItem(row, 0, nameItem);
|
||||
|
||||
// 使用结构体数据填充表格,状态和类型显示中文,并设置居中对齐
|
||||
NumericTableWidgetItem *idItem = new NumericTableWidgetItem(data.id);
|
||||
idItem->setTextAlignment(Qt::AlignCenter); // ID列文字居中显示
|
||||
m_tableWidget->setItem(row, 0, idItem);
|
||||
m_tableWidget->setItem(row, 1, idItem);
|
||||
|
||||
QTableWidgetItem *statusItem = new QTableWidgetItem(getTearStatusText(data.tearStatus));
|
||||
statusItem->setTextAlignment(Qt::AlignCenter); // 状态列文字居中显示
|
||||
m_tableWidget->setItem(row, 1, statusItem);
|
||||
m_tableWidget->setItem(row, 2, statusItem);
|
||||
|
||||
QTableWidgetItem *typeItem = new QTableWidgetItem(getTearTypeText(data.tearType));
|
||||
typeItem->setTextAlignment(Qt::AlignCenter); // 类型列文字居中显示
|
||||
m_tableWidget->setItem(row, 2, typeItem);
|
||||
m_tableWidget->setItem(row, 3, typeItem);
|
||||
|
||||
m_tableWidget->setItem(row, 3, new QTableWidgetItem(data.tearDepth));
|
||||
m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearWidth));
|
||||
m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearLength));
|
||||
// m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.statLineIdx));
|
||||
m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearDepth));
|
||||
m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearWidth));
|
||||
m_tableWidget->setItem(row, 6, new QTableWidgetItem(data.tearLength));
|
||||
|
||||
// 添加时间列
|
||||
QString currentTime = QString::fromStdString(CVrDateUtils::GetStrNowTime(false));
|
||||
QTableWidgetItem *timeItem = new QTableWidgetItem(currentTime);
|
||||
timeItem->setTextAlignment(Qt::AlignCenter);
|
||||
m_tableWidget->setItem(row, 7, timeItem);
|
||||
|
||||
// 设置item的文本颜色
|
||||
for (int i = 0; i < m_tableWidget->horizontalHeader()->count(); i++) {
|
||||
@ -128,15 +136,47 @@ void TearingDataTableWidget::addData(const TearingData &data)
|
||||
item->setForeground(QBrush(Qt::white));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::addData(const QString devName, const TearingData &data)
|
||||
{
|
||||
// 构造键值
|
||||
QString key = devName + ":" + data.id;
|
||||
|
||||
// 禁用排序以提高性能,批量处理后再启用
|
||||
m_tableWidget->setSortingEnabled(false);
|
||||
|
||||
// 查找是否已存在相同设备名称和ID的行
|
||||
int existingRow = -1;
|
||||
if (m_devIdSet.contains(key)) {
|
||||
existingRow = findExistingRowById(devName, data.id);
|
||||
}
|
||||
|
||||
int row;
|
||||
if (existingRow >= 0) {
|
||||
// 如果存在相同设备名称和ID,更新该行
|
||||
row = existingRow;
|
||||
} else {
|
||||
// 如果不存在,插入新行
|
||||
row = m_tableWidget->rowCount();
|
||||
m_tableWidget->insertRow(row);
|
||||
// 添加到集合中
|
||||
m_devIdSet.insert(key);
|
||||
}
|
||||
|
||||
_AddDataToTable(devName, data, row);
|
||||
|
||||
// 重新启用排序
|
||||
m_tableWidget->setSortingEnabled(true);
|
||||
|
||||
// 手动触发一次按ID列倒序排序
|
||||
m_tableWidget->sortItems(1, Qt::DescendingOrder);
|
||||
|
||||
// 检查是否需要限制行数
|
||||
limitRowsIfNeeded();
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::addData(const std::vector<TearingData> &dataList)
|
||||
void TearingDataTableWidget::addData(const QString devName, const std::vector<TearingData> &dataList)
|
||||
{
|
||||
if (dataList.empty()) {
|
||||
return;
|
||||
@ -148,21 +188,21 @@ void TearingDataTableWidget::addData(const std::vector<TearingData> &dataList)
|
||||
|
||||
// 遍历vector中的所有数据并添加到表格
|
||||
for (const auto &data : dataList) {
|
||||
addData(data);
|
||||
addData(devName, data);
|
||||
}
|
||||
|
||||
// 重新启用更新和排序
|
||||
m_tableWidget->setUpdatesEnabled(true);
|
||||
m_tableWidget->setSortingEnabled(true);
|
||||
|
||||
// 手动触发一次排序
|
||||
m_tableWidget->sortItems(0, Qt::AscendingOrder);
|
||||
// 手动触发一次按ID列倒序排序
|
||||
m_tableWidget->sortItems(1, Qt::DescendingOrder);
|
||||
|
||||
// 检查是否需要限制行数
|
||||
limitRowsIfNeeded();
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::addDataBatch(const std::vector<TearingData> &dataList)
|
||||
void TearingDataTableWidget::addDataBatch(const QString devName, const std::vector<TearingData> &dataList)
|
||||
{
|
||||
if (dataList.empty()) {
|
||||
return;
|
||||
@ -180,7 +220,8 @@ void TearingDataTableWidget::addDataBatch(const std::vector<TearingData> &dataLi
|
||||
// 先找出需要新增的数据量
|
||||
int rowsToAdd = 0;
|
||||
for (const auto &data : dataList) {
|
||||
if (findExistingRowById(data.id) < 0) {
|
||||
QString key = devName + ":" + data.id;
|
||||
if (!m_devIdSet.contains(key)) {
|
||||
rowsToAdd++;
|
||||
}
|
||||
}
|
||||
@ -192,62 +233,37 @@ void TearingDataTableWidget::addDataBatch(const std::vector<TearingData> &dataLi
|
||||
|
||||
// 填充数据
|
||||
for (const auto &data : dataList) {
|
||||
// 查找是否已存在相同ID的行
|
||||
int existingRow = findExistingRowById(data.id);
|
||||
// 构造键值
|
||||
QString key = devName + ":" + data.id;
|
||||
|
||||
// 查找是否已存在相同设备名称和ID的行
|
||||
int existingRow = -1;
|
||||
if (m_devIdSet.contains(key)) {
|
||||
existingRow = findExistingRowById(devName, data.id);
|
||||
}
|
||||
|
||||
int row;
|
||||
if (existingRow >= 0) {
|
||||
// 如果存在相同ID,更新该行
|
||||
// 如果存在相同设备名称和ID,更新该行
|
||||
row = existingRow;
|
||||
} else {
|
||||
// 如果不存在,使用新行
|
||||
row = m_tableWidget->rowCount() - rowsToAdd;
|
||||
rowsToAdd--; // 减少剩余需要分配的行数
|
||||
// 添加到集合中
|
||||
m_devIdSet.insert(key);
|
||||
}
|
||||
|
||||
// 使用结构体数据填充表格,状态和类型显示中文,并设置居中对齐
|
||||
NumericTableWidgetItem *idItem = new NumericTableWidgetItem(data.id);
|
||||
idItem->setTextAlignment(Qt::AlignCenter); // ID列文字居中显示
|
||||
m_tableWidget->setItem(row, 0, idItem);
|
||||
|
||||
QTableWidgetItem *statusItem = new QTableWidgetItem(getTearStatusText(data.tearStatus));
|
||||
statusItem->setTextAlignment(Qt::AlignCenter); // 状态列文字居中显示
|
||||
m_tableWidget->setItem(row, 1, statusItem);
|
||||
|
||||
QTableWidgetItem *typeItem = new QTableWidgetItem(getTearTypeText(data.tearType));
|
||||
typeItem->setTextAlignment(Qt::AlignCenter); // 类型列文字居中显示
|
||||
m_tableWidget->setItem(row, 2, typeItem);
|
||||
|
||||
m_tableWidget->setItem(row, 3, new QTableWidgetItem(data.tearDepth));
|
||||
m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearWidth));
|
||||
m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearLength));
|
||||
|
||||
// 设置item的文本颜色
|
||||
for (int i = 0; i < m_tableWidget->horizontalHeader()->count(); i++) {
|
||||
QTableWidgetItem *item = m_tableWidget->item(row, i);
|
||||
if (item) {
|
||||
item->setForeground(QBrush(Qt::white));
|
||||
}
|
||||
}
|
||||
_AddDataToTable(devName, data, row);
|
||||
}
|
||||
|
||||
|
||||
// 重新启用更新和排序
|
||||
m_tableWidget->setUpdatesEnabled(true);
|
||||
m_tableWidget->setSortingEnabled(true);
|
||||
|
||||
// 手动触发一次排序
|
||||
m_tableWidget->sortItems(0, Qt::AscendingOrder);
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::addData(const QJsonObject &json)
|
||||
{
|
||||
// 添加空指针检查,防止在m_tableWidget为nullptr时崩溃
|
||||
if (!m_tableWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
TearingData data = TearingData::fromJsonObject(json);
|
||||
addData(data);
|
||||
// 手动触发一次按ID列倒序排序
|
||||
m_tableWidget->sortItems(1, Qt::DescendingOrder);
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::clearData()
|
||||
@ -260,9 +276,13 @@ void TearingDataTableWidget::clearData()
|
||||
// 清除所有行数据
|
||||
m_tableWidget->setRowCount(0);
|
||||
|
||||
// 重置排序状态
|
||||
m_tableWidget->setSortingEnabled(false);
|
||||
m_tableWidget->setSortingEnabled(true);
|
||||
// 清空集合
|
||||
m_devIdSet.clear();
|
||||
|
||||
// 重置排序状态,默认按ID列倒序排序
|
||||
m_tableWidget->setSortingEnabled(false);
|
||||
m_tableWidget->setSortingEnabled(true);
|
||||
m_tableWidget->sortItems(1, Qt::DescendingOrder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,6 +292,20 @@ void TearingDataTableWidget::setMaximumRows(int maxRows)
|
||||
// m_maxRows = maxRows;
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::removeRowFromSet(int row)
|
||||
{
|
||||
// 从表格中获取设备名称和ID
|
||||
if (row >= 0 && row < m_tableWidget->rowCount()) {
|
||||
QTableWidgetItem *devItem = m_tableWidget->item(row, 0); // 设备名称在第0列
|
||||
QTableWidgetItem *idItem = m_tableWidget->item(row, 1); // ID在第1列
|
||||
|
||||
if (devItem && idItem) {
|
||||
QString key = devItem->text() + ":" + idItem->text();
|
||||
m_devIdSet.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TearingDataTableWidget::limitRowsIfNeeded()
|
||||
{
|
||||
// 添加空指针检查,防止在m_tableWidget为nullptr时崩溃
|
||||
@ -287,6 +321,8 @@ void TearingDataTableWidget::limitRowsIfNeeded()
|
||||
|
||||
// 删除最旧的行(假设新数据在后面)
|
||||
for (int i = 0; i < rowsToDelete; i++) {
|
||||
// 从集合中移除
|
||||
removeRowFromSet(0);
|
||||
m_tableWidget->removeRow(0);
|
||||
}
|
||||
|
||||
@ -301,13 +337,13 @@ QString TearingDataTableWidget::getTearStatusText(const QString &status)
|
||||
if (status == "0" || status.contains("Uknown")) {
|
||||
return "未知";
|
||||
} else if (status == "1" || status.contains("New")) {
|
||||
return "新发现";
|
||||
return "新增";
|
||||
} else if (status == "2" || status.contains("Growing")) {
|
||||
return "正在增长";
|
||||
return "进行";
|
||||
} else if (status == "3" || status.contains("Ended")) {
|
||||
return "撕裂结束";
|
||||
return "结束";
|
||||
} else if (status == "4" || status.contains("Invalid")) {
|
||||
return "无效撕裂";
|
||||
return "无效";
|
||||
}
|
||||
return status; // 如果无法识别,返回原值
|
||||
}
|
||||
@ -325,19 +361,22 @@ QString TearingDataTableWidget::getTearTypeText(const QString &type)
|
||||
return type; // 如果无法识别,返回原值
|
||||
}
|
||||
|
||||
int TearingDataTableWidget::findExistingRowById(const QString &id)
|
||||
int TearingDataTableWidget::findExistingRowById(const QString &devName, const QString &id)
|
||||
{
|
||||
// 在表格中查找具有相同ID的行
|
||||
// 使用二分查找优化性能,假设表格按ID排序
|
||||
int rowCount = m_tableWidget->rowCount();
|
||||
if (rowCount == 0) {
|
||||
return -1;
|
||||
// 构造键值
|
||||
QString key = devName + ":" + id;
|
||||
|
||||
// 使用哈希表快速判断是否存在
|
||||
if (!m_devIdSet.contains(key)) {
|
||||
return -1; // 不存在直接返回-1
|
||||
}
|
||||
|
||||
// 简单的线性查找(在实际应用中,如果数据量很大,可以考虑使用哈希表或其他数据结构来优化)
|
||||
// 如果存在,则在表格中查找具体行号(虽然概率很小,但为了确保数据一致性仍需查找)
|
||||
int rowCount = m_tableWidget->rowCount();
|
||||
for (int row = 0; row < rowCount; ++row) {
|
||||
QTableWidgetItem *item = m_tableWidget->item(row, 0); // ID在第0列
|
||||
if (item && item->text() == id) {
|
||||
QTableWidgetItem *devItem = m_tableWidget->item(row, 0); // 设备名称在第0列
|
||||
QTableWidgetItem *idItem = m_tableWidget->item(row, 1); // ID在第1列
|
||||
if (devItem && idItem && devItem->text() == devName && idItem->text() == id) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@
|
||||
#include <QHeaderView>
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
#include <QSet>
|
||||
#include <vector>
|
||||
#include "IStatusUpdate.h"
|
||||
#include "VrDateUtils.h"
|
||||
|
||||
// 自定义TableWidgetItem类,支持按数字值排序
|
||||
class NumericTableWidgetItem : public QTableWidgetItem
|
||||
@ -36,30 +38,34 @@ public:
|
||||
explicit TearingDataTableWidget(QWidget *parent = nullptr);
|
||||
~TearingDataTableWidget();
|
||||
|
||||
// 添加单条数据
|
||||
void addData(const TearingData &data);
|
||||
|
||||
|
||||
// 添加多条数据(自动选择优化方法)
|
||||
void addData(const std::vector<TearingData> &dataList);
|
||||
|
||||
// 添加单条JSON数据
|
||||
void addData(const QJsonObject &data);
|
||||
|
||||
void addData(const QString devName, const TearingData &dataList);
|
||||
|
||||
// 添加多条数据(自动选择优化方法)
|
||||
void addData(const QString devName, const std::vector<TearingData> &dataList);
|
||||
|
||||
// 批量添加数据,优化大量数据处理性能
|
||||
void addDataBatch(const std::vector<TearingData> &dataList);
|
||||
void addDataBatch(const QString devName, const std::vector<TearingData> &dataList);
|
||||
|
||||
// 清除所有数据
|
||||
void clearData();
|
||||
|
||||
// 设置表格最大行数限制,防止内存占用过大
|
||||
void setMaximumRows(int maxRows);
|
||||
|
||||
// 从集合中移除指定行的设备ID组合
|
||||
void removeRowFromSet(int row);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void setupTable();
|
||||
|
||||
void _AddDataToTable(const QString devName, const TearingData &data, int row);
|
||||
|
||||
QString getTearStatusText(const QString &status);
|
||||
QString getTearTypeText(const QString &type);
|
||||
int findExistingRowById(const QString &id);
|
||||
int findExistingRowById(const QString &devName, const QString &id);
|
||||
|
||||
// 内存管理相关方法
|
||||
void limitRowsIfNeeded();
|
||||
@ -67,8 +73,14 @@ private:
|
||||
// 排序相关的私有方法
|
||||
void connectHeaderSignals();
|
||||
|
||||
// 与服务端颜色协调的颜色数组
|
||||
QColor m_tearColors[10];
|
||||
|
||||
QTableWidget *m_tableWidget;
|
||||
int m_maxRows = -1; // 最大行数限制,-1表示无限制
|
||||
|
||||
// 使用QSet存储设备名称和ID的组合,格式为"设备名:ID"
|
||||
QSet<QString> m_devIdSet;
|
||||
};
|
||||
|
||||
#endif // TEARINGDATATABLEWIDGET_H
|
||||
|
||||
@ -581,9 +581,7 @@ void BeltTearingPresenter::sendTearingResults(const std::vector<SSG_beltTearingI
|
||||
|
||||
// 发送到所有连接的客户端
|
||||
bool success = m_tcpServer->SendAllData(package.constData(), package.size());
|
||||
if (success) {
|
||||
LOG_DEBUG("Sent tearing results (%d bytes) to %d clients\n", package.size(), m_clients.size());
|
||||
} else {
|
||||
if (!success) {
|
||||
LOG_WARNING("Failed to send tearing results to all clients\n");
|
||||
}
|
||||
}
|
||||
@ -808,9 +806,7 @@ void BeltTearingPresenter::sendImageToClients(const QImage& image)
|
||||
|
||||
// 发送给所有连接的客户端
|
||||
bool success = m_tcpServer->SendAllData(packet.constData(), packet.size());
|
||||
if (success) {
|
||||
LOG_DEBUG("Sent point cloud image (%d bytes) to %d clients\n", packet.size(), m_clients.size());
|
||||
} else {
|
||||
if (!success) {
|
||||
LOG_WARNING("Failed to send image data to all clients\n");
|
||||
}
|
||||
|
||||
@ -874,6 +870,37 @@ void BeltTearingPresenter::handleAlgorithmParameterUpdate(const QByteArray& para
|
||||
} else if (command == "getServerInfo") {
|
||||
// 处理服务器信息获取请求
|
||||
handleGetServerInfo(paramObj);
|
||||
} else if (command == "resetDetect") {
|
||||
// 处理重新检测请求
|
||||
LOG_INFO("Received reset detect command from client\n");
|
||||
ResetDetect();
|
||||
|
||||
// 发送响应给客户端
|
||||
QJsonObject responseObj;
|
||||
responseObj["command"] = "resetDetectResponse";
|
||||
responseObj["status"] = "success";
|
||||
responseObj["message"] = "Detection reset completed";
|
||||
responseObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
|
||||
QJsonDocument responseDoc(responseObj);
|
||||
QByteArray responseData = responseDoc.toJson();
|
||||
|
||||
// 构建数据包并发送给所有客户端
|
||||
if (!m_clients.isEmpty() && m_tcpServer) {
|
||||
QByteArray package;
|
||||
QDataStream stream(&package, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::BigEndian);
|
||||
stream << quint8(static_cast<quint8>(ByteDataType::Text)) << quint32(responseData.size());
|
||||
stream.writeRawData(responseData.constData(), responseData.size());
|
||||
package.append("___END___\r\n");
|
||||
|
||||
bool success = m_tcpServer->SendAllData(package.constData(), package.size());
|
||||
if (success) {
|
||||
LOG_INFO("Reset detect response sent to clients\n");
|
||||
} else {
|
||||
LOG_WARNING("Failed to send reset detect response to clients\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING("Unknown command: %s\n", command.toStdString().c_str());
|
||||
return;
|
||||
@ -1120,7 +1147,7 @@ int BeltTearingPresenter::_DetectTask()
|
||||
// 临时存储从队列中取出的数据,避免重复处理
|
||||
std::vector<SVzNL3DLaserLine> algorithmDataCache;
|
||||
std::vector<std::vector<SVzNL3DPosition>> imageScanLines;
|
||||
|
||||
|
||||
// 从队列中获取数据
|
||||
{
|
||||
std::lock_guard<std::mutex> queueLock(m_queueMutex);
|
||||
@ -1158,9 +1185,9 @@ int BeltTearingPresenter::_DetectTask()
|
||||
if (line.p3DPoint && line.nPointCount > 0) {
|
||||
std::vector<SVzNL3DPosition> linePoints;
|
||||
linePoints.reserve(line.nPointCount); // 预分配内存提高效率
|
||||
|
||||
|
||||
SVzNL3DPosition* p3DPoints = static_cast<SVzNL3DPosition*>(line.p3DPoint);
|
||||
|
||||
|
||||
// 使用更高效的批量复制
|
||||
linePoints.assign(p3DPoints, p3DPoints + line.nPointCount);
|
||||
imageScanLines.emplace_back(std::move(linePoints)); // 使用move避免拷贝
|
||||
@ -1168,13 +1195,6 @@ int BeltTearingPresenter::_DetectTask()
|
||||
}
|
||||
}
|
||||
|
||||
// 使用lambda线程分离图像处理和算法处理
|
||||
std::thread imageThread([this, imageScanLines]() {
|
||||
std::vector<std::vector<SVzNL3DPoint>> emptyResults; // 空的检测结果
|
||||
QImage image = PointCloudImageUtils::GeneratePointCloudImage(imageScanLines, emptyResults, 800, 600);
|
||||
sendImageToClients(image);
|
||||
});
|
||||
|
||||
// 调用SDK算法进行皮带撕裂检测
|
||||
int errorCode = 0;
|
||||
std::vector<SSG_beltTearingInfo> allTearings;
|
||||
@ -1213,15 +1233,17 @@ int BeltTearingPresenter::_DetectTask()
|
||||
);
|
||||
|
||||
// 合并各个撕裂结果容器
|
||||
// _MergeAndReplace(allTearings, m_beltTearings_new);
|
||||
// _MergeAndReplace(allTearings, m_beltTearings_growing);
|
||||
// _MergeAndReplace(allTearings, m_beltTearings_ended);
|
||||
#if 1
|
||||
_MergeAndReplace(allTearings, m_beltTearings_new);
|
||||
_MergeAndReplace(allTearings, m_beltTearings_growing);
|
||||
_MergeAndReplace(allTearings, m_beltTearings_ended);
|
||||
// _MergeAndReplace(allTearings, m_beltTearings_unknown);
|
||||
|
||||
#else
|
||||
allTearings.insert(allTearings.end(), m_beltTearings_new.begin(), m_beltTearings_new.end());
|
||||
allTearings.insert(allTearings.end(), m_beltTearings_growing.begin(), m_beltTearings_growing.end());
|
||||
allTearings.insert(allTearings.end(), m_beltTearings_ended.begin(), m_beltTearings_ended.end());
|
||||
// allTearings.insert(allTearings.end(), m_beltTearings_unknown.begin(), m_beltTearings_unknown.end());
|
||||
#endif
|
||||
}
|
||||
|
||||
// 发送检测结果
|
||||
@ -1229,7 +1251,7 @@ int BeltTearingPresenter::_DetectTask()
|
||||
sendTearingResults(allTearings);
|
||||
SendDetectionResultToRobot(allTearings); // 发送检测结果到机械臂
|
||||
}
|
||||
|
||||
|
||||
// 释放深拷贝的点云数据
|
||||
for (auto& algorithmData : algorithmDataCache) {
|
||||
if (algorithmData.p3DPosition) {
|
||||
@ -1238,10 +1260,10 @@ int BeltTearingPresenter::_DetectTask()
|
||||
}
|
||||
}
|
||||
|
||||
// 等待图像线程完成
|
||||
if (imageThread.joinable()) {
|
||||
imageThread.join();
|
||||
}
|
||||
// 在算法处理完成后,生成带撕裂检测结果的图像
|
||||
QImage image = PointCloudImageUtils::GeneratePointCloudImage(imageScanLines, allTearings, 800, 600);
|
||||
sendImageToClients(image);
|
||||
|
||||
return 0; // 成功完成检测任务
|
||||
}
|
||||
|
||||
|
||||
@ -6,13 +6,14 @@
|
||||
#include "VrLog.h"
|
||||
|
||||
#include "VrTimeUtils.h"
|
||||
#include "beltTearingDetection_Export.h"
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
QImage PointCloudImageUtils::GeneratePointCloudImage(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
|
||||
const std::vector<std::vector<SVzNL3DPoint>>& detectionResults,
|
||||
const std::vector<SSG_beltTearingInfo>& beltTearings,
|
||||
int imageWidth, int imageHeight)
|
||||
{
|
||||
if (scanLines.empty() || imageWidth <= 0 || imageHeight <= 0) {
|
||||
@ -23,7 +24,7 @@ QImage PointCloudImageUtils::GeneratePointCloudImage(const std::vector<std::vect
|
||||
// 快速计算点云范围
|
||||
double xMin, xMax, yMin, yMax;
|
||||
if (!CalculateRangeFast(scanLines, xMin, xMax, yMin, yMax)) {
|
||||
LOG_WARNING("No valid points found in scan lines\n");
|
||||
// LOG_WARNING("No valid points found in scan lines, arg=%d count=%d\n", scanLines.size(), scanLines.size() ? scanLines[0].size() : 0);
|
||||
return QImage();
|
||||
}
|
||||
|
||||
@ -46,17 +47,24 @@ QImage PointCloudImageUtils::GeneratePointCloudImage(const std::vector<std::vect
|
||||
DrawPointCloudDirect(image, scanLines, xMin, xMax, yMin, yMax, imageWidth, imageHeight);
|
||||
|
||||
// 绘制检测结果(如果需要)
|
||||
if (!detectionResults.empty()) {
|
||||
QPainter painter(&image);
|
||||
DrawLapWeldResults(painter, detectionResults, xMin, xMax, yMin, yMax, imageWidth, imageHeight);
|
||||
QPainter painter(&image);
|
||||
|
||||
if (!beltTearings.empty()) {
|
||||
DrawBeltTearingResults(painter, beltTearings, xMin, xMax, yMin, yMax, imageWidth, imageHeight);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
bool PointCloudImageUtils::CalculateRangeFast(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
|
||||
double& xMin, double& xMax,
|
||||
double& yMin, double& yMax)
|
||||
double& xMin, double& xMax, double& yMin, double& yMax)
|
||||
{
|
||||
if (scanLines.empty()) {
|
||||
// 设置默认范围以避免无效计算
|
||||
xMin = xMax = yMin = yMax = 0.0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 使用局部变量减少内存写入
|
||||
double localXMin = std::numeric_limits<double>::max();
|
||||
double localXMax = std::numeric_limits<double>::lowest();
|
||||
@ -107,6 +115,18 @@ void PointCloudImageUtils::DrawPointCloudDirect(QImage& image,
|
||||
{
|
||||
if (scanLines.empty()) return;
|
||||
|
||||
// 检查范围是否有效,避免除零错误
|
||||
if (xMax <= xMin || yMax <= yMin) {
|
||||
LOG_WARNING("Invalid range for drawing: xMin=%f, xMax=%f, yMin=%f, yMax=%f\n", xMin, xMax, yMin, yMax);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查图像尺寸是否有效
|
||||
if (imageWidth <= 0 || imageHeight <= 0) {
|
||||
LOG_WARNING("Invalid image dimensions: width=%d, height=%d\n", imageWidth, imageHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
// 预计算缩放因子和偏移量
|
||||
const double xScale = imageWidth / (xMax - xMin);
|
||||
const double yScale = imageHeight / (yMax - yMin);
|
||||
@ -170,8 +190,20 @@ void PointCloudImageUtils::DrawLapWeldResults(QPainter& painter,
|
||||
{
|
||||
if (weldResults.empty()) return;
|
||||
|
||||
double xScale = (xMax - xMin) / imageWidth;
|
||||
double yScale = (yMax - yMin) / imageHeight;
|
||||
// 检查范围是否有效,避免除零错误
|
||||
if (xMax <= xMin || yMax <= yMin) {
|
||||
LOG_WARNING("Invalid range for drawing: xMin=%f, xMax=%f, yMin=%f, yMax=%f\n", xMin, xMax, yMin, yMax);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查图像尺寸是否有效
|
||||
if (imageWidth <= 0 || imageHeight <= 0) {
|
||||
LOG_WARNING("Invalid image dimensions: width=%d, height=%d\n", imageWidth, imageHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
double xScale = imageWidth / (xMax - xMin);
|
||||
double yScale = imageHeight / (yMax - yMin);
|
||||
|
||||
// 使用不同颜色绘制每条焊缝
|
||||
QColor weldColors[] = {
|
||||
@ -195,10 +227,10 @@ void PointCloudImageUtils::DrawLapWeldResults(QPainter& painter,
|
||||
|
||||
// 绘制焊缝线段
|
||||
for (size_t j = 1; j < weldLine.size(); j++) {
|
||||
int px1 = (int)((weldLine[j-1].x - xMin) / xScale);
|
||||
int py1 = (int)((weldLine[j-1].y - yMin) / yScale);
|
||||
int px2 = (int)((weldLine[j].x - xMin) / xScale);
|
||||
int py2 = (int)((weldLine[j].y - yMin) / yScale);
|
||||
int px1 = (int)((weldLine[j-1].x - xMin) * xScale);
|
||||
int py1 = (int)((weldLine[j-1].y - yMin) * yScale);
|
||||
int px2 = (int)((weldLine[j].x - xMin) * xScale);
|
||||
int py2 = (int)((weldLine[j].y - yMin) * yScale);
|
||||
|
||||
if (px1 >= 0 && px1 < imageWidth && py1 >= 0 && py1 < imageHeight &&
|
||||
px2 >= 0 && px2 < imageWidth && py2 >= 0 && py2 < imageHeight) {
|
||||
@ -209,8 +241,8 @@ void PointCloudImageUtils::DrawLapWeldResults(QPainter& painter,
|
||||
// 在起点和终点绘制标记
|
||||
if (!weldLine.empty()) {
|
||||
// 起点标记 - 圆形
|
||||
int startX = (int)((weldLine[0].x - xMin) / xScale);
|
||||
int startY = (int)((weldLine[0].y - yMin) / yScale);
|
||||
int startX = (int)((weldLine[0].x - xMin) * xScale);
|
||||
int startY = (int)((weldLine[0].y - yMin) * yScale);
|
||||
if (startX >= 0 && startX < imageWidth && startY >= 0 && startY < imageHeight) {
|
||||
painter.setPen(QPen(weldColor, 2));
|
||||
painter.setBrush(QBrush(weldColor));
|
||||
@ -218,8 +250,8 @@ void PointCloudImageUtils::DrawLapWeldResults(QPainter& painter,
|
||||
}
|
||||
|
||||
// 终点标记 - 方形
|
||||
int endX = (int)((weldLine.back().x - xMin) / xScale);
|
||||
int endY = (int)((weldLine.back().y - yMin) / yScale);
|
||||
int endX = (int)((weldLine.back().x - xMin) * xScale);
|
||||
int endY = (int)((weldLine.back().y - yMin) * yScale);
|
||||
if (endX >= 0 && endX < imageWidth && endY >= 0 && endY < imageHeight) {
|
||||
painter.setPen(QPen(weldColor, 2));
|
||||
painter.setBrush(QBrush(weldColor));
|
||||
@ -228,3 +260,68 @@ void PointCloudImageUtils::DrawLapWeldResults(QPainter& painter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PointCloudImageUtils::DrawBeltTearingResults(QPainter& painter,
|
||||
const std::vector<SSG_beltTearingInfo>& tearings,
|
||||
double xMin, double xMax, double yMin, double yMax,
|
||||
int imageWidth, int imageHeight)
|
||||
{
|
||||
if (tearings.empty()) return;
|
||||
|
||||
// 检查范围是否有效,避免除零错误
|
||||
if (xMax <= xMin || yMax <= yMin) {
|
||||
LOG_WARNING("Invalid range for drawing: xMin=%f, xMax=%f, yMin=%f, yMax=%f\n", xMin, xMax, yMin, yMax);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查图像尺寸是否有效
|
||||
if (imageWidth <= 0 || imageHeight <= 0) {
|
||||
LOG_WARNING("Invalid image dimensions: width=%d, height=%d\n", imageWidth, imageHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
double xScale = imageWidth / (xMax - xMin);
|
||||
double yScale = imageHeight / (yMax - yMin);
|
||||
|
||||
// 使用10种协调的颜色根据撕裂ID进行绘制
|
||||
QColor tearColors[] = {
|
||||
QColor(255, 105, 97), // 珊瑚红
|
||||
QColor(255, 160, 122), // 浅鲑鱼色
|
||||
QColor(173, 216, 230), // 浅蓝色
|
||||
QColor(144, 238, 144), // 浅绿色
|
||||
QColor(255, 182, 193), // 浅粉色
|
||||
QColor(221, 160, 221), // 梅花色
|
||||
QColor(255, 215, 0), // 金色
|
||||
QColor(240, 128, 128), // 玫瑰色
|
||||
QColor(135, 206, 250), // 天蓝色
|
||||
QColor(127, 255, 212) // 碧绿色
|
||||
};
|
||||
int numColors = sizeof(tearColors) / sizeof(tearColors[0]);
|
||||
|
||||
for (size_t i = 0; i < tearings.size(); i++) {
|
||||
const auto& tearing = tearings[i];
|
||||
// 根据撕裂ID选择颜色,确保相同ID使用相同颜色
|
||||
QColor tearColor = tearColors[tearing.tearID % numColors];
|
||||
|
||||
// 如果撕裂信息包含点集,则绘制点(每隔一定数量的点绘制一个,减少密度)
|
||||
#if OUTPUT_TEARING_POINTS
|
||||
if (!tearing.pts.empty()) {
|
||||
// 每隔3个点绘制一个点,减少点的密度
|
||||
const int pointInterval = 3;
|
||||
for (size_t idx = 0; idx < tearing.pts.size(); idx += pointInterval) {
|
||||
const auto& point = tearing.pts[idx];
|
||||
int px = (int)((point.pt3D.x - xMin) * xScale);
|
||||
int py = (int)((point.pt3D.y - yMin) * yScale);
|
||||
|
||||
if (px >= 0 && px < imageWidth && py >= 0 && py < imageHeight) {
|
||||
// 设置画笔和画刷用于绘制点
|
||||
painter.setPen(QPen(tearColor, 1)); // 减小画笔宽度
|
||||
painter.setBrush(QBrush(tearColor));
|
||||
// 绘制点为小圆圈,减小点的大小
|
||||
painter.drawEllipse(px - 1, py - 1, 2, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include "VZNL_Types.h"
|
||||
#include "SG_baseDataType.h"
|
||||
#include "beltTearingDetection_Export.h"
|
||||
|
||||
struct PointRenderData {
|
||||
double x, y;
|
||||
@ -21,7 +22,7 @@ class PointCloudImageUtils
|
||||
public:
|
||||
// 点云转图像 - 使用std::vector格式的扫描线数据
|
||||
static QImage GeneratePointCloudImage(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
|
||||
const std::vector<std::vector<SVzNL3DPoint>>& detectionResults,
|
||||
const std::vector<SSG_beltTearingInfo>& beltTearings,
|
||||
int imageWidth, int imageHeight);
|
||||
|
||||
|
||||
@ -55,11 +56,11 @@ private:
|
||||
double xMin, double xMax, double yMin, double yMax,
|
||||
int imageWidth, int imageHeight);
|
||||
|
||||
// 绘制scan lines点云数据 (原始版本)
|
||||
static void DrawScanLinesPointCloud(QPainter& painter,
|
||||
const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
|
||||
double xMin, double xMax, double yMin, double yMax,
|
||||
int imageWidth, int imageHeight);
|
||||
// 绘制皮带撕裂检测结果
|
||||
static void DrawBeltTearingResults(QPainter& painter,
|
||||
const std::vector<SSG_beltTearingInfo>& tearings,
|
||||
double xMin, double xMax, double yMin, double yMax,
|
||||
int imageWidth, int imageHeight);
|
||||
|
||||
// 优化版本:批量绘制点云
|
||||
static void DrawPointCloudOptimized(QPainter& painter,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#define VERSION_H
|
||||
|
||||
#define BELT_TEARING_SERVER_VERSION_STRING "2.0.1"
|
||||
#define BELT_TEARING_SERVER_VERSION_BUILD "4"
|
||||
#define BELT_TEARING_SERVER_VERSION_BUILD "5"
|
||||
#define BELT_TEARING_SERVER_PRODUCT_NAME "BeltTearingServer"
|
||||
#define BELT_TEARING_SERVER_COMPANY_NAME "VisionRobot"
|
||||
#define BELT_TEARING_SERVER_COPYRIGHT "Copyright (C) 2024 VisionRobot. All rights reserved."
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||
|
||||
#define MyAppName "BeltTearingApp"
|
||||
#define MyAppVersion "2.0.1.4"
|
||||
#define MyAppVersion "2.0.1.5"
|
||||
#define MyAppPublisher ""
|
||||
#define MyAppURL ""
|
||||
#define MyAppExeName "BeltTearingApp.exe"
|
||||
@ -12,7 +12,7 @@
|
||||
; NOTE: The value of AppId uniquely identifies this application.
|
||||
; Do not use the same AppId value in installers for other applications.
|
||||
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||
AppId={{7EFE68AC-05BD-4BA2-B420-2C71094031A1}
|
||||
AppId={{7EFE68AC-05BD-4BA2-B420-2C71094031A1}}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppVerName={#MyAppName}_V{#MyAppVersion}
|
||||
|
||||
@ -118,28 +118,35 @@ cat > ${POSTINST_PATH} << 'EOF'
|
||||
echo "配置 BeltTearingServer 应用程序..."
|
||||
|
||||
# 安装并启用 belttearingserver.service
|
||||
if [ -f /opt/belttearingserver/belttearingserver.service ]; then
|
||||
SERVICE_FILE="/opt/belttearingserver/belttearingserver.service"
|
||||
TARGET_SERVICE_FILE="/etc/systemd/system/belttearingserver.service"
|
||||
|
||||
if [ -f "$SERVICE_FILE" ]; then
|
||||
echo "安装 belttearingserver.service..."
|
||||
|
||||
# 检查服务是否已经存在,如果存在则先停止并禁用
|
||||
if systemctl is-active --quiet belttearingserver.service; then
|
||||
echo "检测到已运行的 belttearingserver.service,正在停止..."
|
||||
if systemctl is-active --quiet belttearingserver.service 2>/dev/null; then
|
||||
echo "检测到已运行的 belttearingserver.service,正在停止..."
|
||||
systemctl stop belttearingserver.service
|
||||
fi
|
||||
|
||||
if systemctl is-enabled --quiet belttearingserver.service; then
|
||||
echo "检测到已启用的 belttearingserver.service,正在禁用..."
|
||||
if systemctl is-enabled --quiet belttearingserver.service 2>/dev/null; then
|
||||
echo "检测到已启用的 belttearingserver.service,正在禁用..."
|
||||
systemctl disable belttearingserver.service
|
||||
fi
|
||||
|
||||
# 复制服务文件
|
||||
cp /opt/belttearingserver/belttearingserver.service /etc/systemd/system/
|
||||
cp "$SERVICE_FILE" "$TARGET_SERVICE_FILE"
|
||||
# 设置正确的权限
|
||||
chmod 644 "$TARGET_SERVICE_FILE"
|
||||
systemctl daemon-reload
|
||||
systemctl enable belttearingserver.service
|
||||
systemctl start belttearingserver.service
|
||||
echo "belttearingserver.service 已安装并设置为开机自启"
|
||||
else
|
||||
echo "错误: 未找到 belttearingserver.service 文件"
|
||||
echo "请检查文件是否存在: $SERVICE_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "BeltTearingServer 应用程序安装完成!"
|
||||
@ -164,11 +171,17 @@ rm -f /etc/systemd/system/belttearingserver.service
|
||||
# 重新加载systemd
|
||||
systemctl daemon-reload
|
||||
|
||||
# 清理 /opt/belttearingserver 目录
|
||||
rm -rf /opt/belttearingserver
|
||||
# 只有在完全卸载时才删除 /opt/belttearingserver 目录
|
||||
if [ "$1" = "remove" ]; then
|
||||
# 清理 /opt/belttearingserver 目录
|
||||
rm -rf /opt/belttearingserver
|
||||
echo "已完全卸载 BeltTearingServer 应用程序"
|
||||
else
|
||||
echo "更新无需删除应用程序"
|
||||
fi
|
||||
|
||||
echo "BeltTearingServer 应用程序卸载完成!"
|
||||
echo "端口映射配置已清理"
|
||||
|
||||
EOF
|
||||
|
||||
chmod +x ${POSTRM_PATH}
|
||||
|
||||
@ -108,6 +108,10 @@ int CVrEyeDevice::OpenDevice(const char* sIP, bool bRGBD, bool bSwing, bool bFil
|
||||
VzNL_BeginDetectLaser(m_pHandle);
|
||||
VzNL_EnableSwingMotor(m_pHandle, bSwing ? VzTrue : VzFalse);
|
||||
|
||||
VzNL_EnableLaserLight(m_pHandle, VzTrue);
|
||||
VzBool bRet = VzNL_IsEnableLaserLight(m_pHandle);
|
||||
LOG_DEBUG("EnableLaserLight ret : %d\n", bRet);
|
||||
|
||||
SVzNLVersionInfo sVersionInfo;
|
||||
VzNL_GetVersion(m_pHandle, &sVersionInfo);
|
||||
LOG_DEBUG("version : %s\n", sVersionInfo.szSDKVersion);
|
||||
@ -155,6 +159,7 @@ int CVrEyeDevice::StartDetect(VzNL_AutoOutputLaserLineExCB fCallFunc, EVzResultD
|
||||
{
|
||||
int nErrCode = SUCCESS;
|
||||
if(!m_pHandle) return ERRCODE(DEV_NO_OPEN);
|
||||
VzNL_SetLaserLight(m_pHandle, VzTrue);
|
||||
LOG_DEBUG("StartDetect eDataType: %d\n", eDataType);
|
||||
nErrCode = VzNL_StartAutoDetectEx(m_pHandle, eDataType, keFlipType_None, fCallFunc, param);
|
||||
return nErrCode;
|
||||
|
||||
@ -9,6 +9,11 @@ namespace CVrDateUtils
|
||||
*/
|
||||
std::string GetNowTime();
|
||||
|
||||
/**
|
||||
* 获取时间:年-月-日 时:分:秒
|
||||
*/
|
||||
std::string GetStrNowTime(bool bYear = true);
|
||||
|
||||
/**
|
||||
* 获取微妙时间戳
|
||||
*/
|
||||
|
||||
@ -26,6 +26,43 @@ std::string CVrDateUtils::GetNowTime()
|
||||
return std::string(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间:年-月-日 时:分:秒
|
||||
*/
|
||||
std::string CVrDateUtils::GetStrNowTime(bool bYear)
|
||||
{
|
||||
time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
#ifdef _WIN32
|
||||
struct tm ptminfo;
|
||||
localtime_s(&ptminfo, &tt);
|
||||
#else
|
||||
struct tm ptminfo = *(localtime(&tt));
|
||||
#endif
|
||||
char date[60] = { 0 };
|
||||
#ifdef _WIN32
|
||||
if (bYear)
|
||||
{
|
||||
sprintf_s(date, "%04d-%02d-%02d %02d:%02d:%02d", ptminfo.tm_year + 1900, \
|
||||
ptminfo.tm_mon + 1, ptminfo.tm_mday, ptminfo.tm_hour, ptminfo.tm_min, ptminfo.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf_s(date, "%02d-%02d %02d:%02d:%02d", ptminfo.tm_mon + 1, ptminfo.tm_mday, ptminfo.tm_hour, ptminfo.tm_min, ptminfo.tm_sec);
|
||||
}
|
||||
#else
|
||||
if (bYear)
|
||||
{
|
||||
sprintf(date, "%04d-%02d-%02d %02d:%02d:%02d", ptminfo.tm_year + 1900, \
|
||||
ptminfo.tm_mon + 1, ptminfo.tm_mday, ptminfo.tm_hour, ptminfo.tm_min, ptminfo.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(date, "%02d-%02d %02d:%02d:%02d", ptminfo.tm_mon + 1, ptminfo.tm_mday, ptminfo.tm_hour, ptminfo.tm_min, ptminfo.tm_sec);
|
||||
}
|
||||
#endif
|
||||
return std::string(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微妙时间戳
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user