678 lines
22 KiB
C++
678 lines
22 KiB
C++
#include "TunnelChannelPresenter.h"
|
||
#include "VrLog.h"
|
||
#include "VrTimeUtils.h"
|
||
#include "VrError.h"
|
||
#include "PointCloudImageUtils.h"
|
||
#include <QCoreApplication>
|
||
#include <QDir>
|
||
#include <algorithm>
|
||
|
||
TunnelChannelPresenter::TunnelChannelPresenter(QObject *parent)
|
||
: BasePresenter(parent)
|
||
, m_pConfigManager(nullptr)
|
||
, m_pHikDevice(nullptr)
|
||
, m_bHikConnected(false)
|
||
, m_pHikReconnectTimer(nullptr)
|
||
, m_pDetectPresenter(nullptr)
|
||
{
|
||
// 连接跨线程信号槽(使用QueuedConnection确保在主线程执行)
|
||
connect(this, &TunnelChannelPresenter::sigHikImageUpdated,
|
||
this, &TunnelChannelPresenter::onHikImageUpdatedInMainThread,
|
||
Qt::QueuedConnection);
|
||
connect(this, &TunnelChannelPresenter::sigHikStatusChanged,
|
||
this, &TunnelChannelPresenter::onHikStatusChangedInMainThread,
|
||
Qt::QueuedConnection);
|
||
connect(this, &TunnelChannelPresenter::sigHikException,
|
||
this, &TunnelChannelPresenter::onHikExceptionInMainThread,
|
||
Qt::QueuedConnection);
|
||
|
||
LOG_INFO("TunnelChannelPresenter created\n");
|
||
}
|
||
|
||
TunnelChannelPresenter::~TunnelChannelPresenter()
|
||
{
|
||
// 停止海康预览并清理设备
|
||
if (m_pHikDevice) {
|
||
m_pHikDevice->StopPreview();
|
||
m_pHikDevice->Logout();
|
||
m_pHikDevice->CleanupSDK();
|
||
delete m_pHikDevice;
|
||
m_pHikDevice = nullptr;
|
||
}
|
||
|
||
// 停止海康重连定时器
|
||
if (m_pHikReconnectTimer) {
|
||
m_pHikReconnectTimer->stop();
|
||
delete m_pHikReconnectTimer;
|
||
m_pHikReconnectTimer = nullptr;
|
||
}
|
||
|
||
// 清理配置管理器
|
||
if (m_pConfigManager) {
|
||
delete m_pConfigManager;
|
||
m_pConfigManager = nullptr;
|
||
}
|
||
|
||
// 清理检测处理器
|
||
if (m_pDetectPresenter) {
|
||
delete m_pDetectPresenter;
|
||
m_pDetectPresenter = nullptr;
|
||
}
|
||
|
||
LOG_INFO("TunnelChannelPresenter destroyed\n");
|
||
}
|
||
|
||
int TunnelChannelPresenter::InitApp()
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::InitApp() - Starting initialization\n");
|
||
|
||
// 1. 初始化配置管理器
|
||
m_pConfigManager = new ConfigManager();
|
||
if (!m_pConfigManager->Initialize()) {
|
||
LOG_ERR("Failed to initialize ConfigManager\n");
|
||
return ERR_CODE(DEV_OPEN_ERR);
|
||
}
|
||
|
||
// 设置配置变化通知
|
||
m_pConfigManager->SetConfigChangeNotify(this);
|
||
|
||
// 2. 初始化海康设备
|
||
int hikResult = InitHikDevice();
|
||
if (hikResult != 0) {
|
||
LOG_WARN("Failed to initialize HikDevice, error: %d. Hik camera will not be available.\n", hikResult);
|
||
// 海康SDK初始化失败不阻止程序运行
|
||
}
|
||
|
||
// 3. 初始化3D相机(使用BasePresenter的InitCamera)
|
||
ConfigResult config = m_pConfigManager->GetCurrentConfig();
|
||
std::vector<DeviceInfo> cameraList = config.cameraList;
|
||
|
||
// 如果没有配置相机,添加一个空配置让设备自动搜索第一个相机
|
||
if (cameraList.empty()) {
|
||
DeviceInfo autoSearchCamera;
|
||
autoSearchCamera.name = "相机";
|
||
autoSearchCamera.ip = ""; // 空IP会触发自动搜索
|
||
cameraList.push_back(autoSearchCamera);
|
||
LOG_INFO("No camera configured, will auto search first available camera\n");
|
||
}
|
||
|
||
// 不需要RGB,需要摆动
|
||
int cameraResult = InitCamera(cameraList, false, true);
|
||
if (cameraResult != 0) {
|
||
LOG_WARN("Failed to initialize 3D cameras, error: %d\n", cameraResult);
|
||
}
|
||
|
||
// 通知相机数量
|
||
OnCameraCountChanged(static_cast<int>(cameraList.size()));
|
||
|
||
// 4. 初始化海康相机
|
||
if (m_pHikDevice) {
|
||
HikCameraConfig hikConfig;
|
||
bool hasHikConfig = false;
|
||
|
||
if (!config.hikCameraList.empty() && !config.hikCameraList[0].ip.empty()) {
|
||
// 使用配置文件中的海康相机配置
|
||
hikConfig = config.hikCameraList[0];
|
||
hasHikConfig = hikConfig.enabled;
|
||
LOG_INFO("Using configured Hik camera: %s\n", hikConfig.ip.c_str());
|
||
} else {
|
||
// 没有配置IP,提示用户配置
|
||
LOG_WARN("No Hik camera IP configured\n");
|
||
OnStatusUpdate("未配置2D相机IP");
|
||
}
|
||
|
||
int connectResult = ConnectHikCamera(hikConfig);
|
||
if (connectResult == 0) {
|
||
m_bHikConnected = true;
|
||
NotifyHikCameraStatus(true);
|
||
LOG_INFO("Hik camera connected successfully\n");
|
||
|
||
// 关闭OSD显示(通道名称和时间)
|
||
int osdResult = m_pHikDevice->ConfigureOSD(false, false);
|
||
if (osdResult != 0) {
|
||
LOG_WARN("Failed to configure OSD, error: %d\n", osdResult);
|
||
}
|
||
|
||
// 开始实时预览(根据是否设置窗口句柄选择渲染方式)
|
||
if (m_hHikDisplayWnd) {
|
||
StartHikPreviewEx(m_hHikDisplayWnd); // 硬件渲染,低延迟
|
||
} else {
|
||
StartHikPreview(); // 软件解码回调
|
||
}
|
||
} else {
|
||
LOG_WARN("Failed to connect Hik camera, will retry later\n");
|
||
NotifyHikCameraStatus(false);
|
||
m_bHikConnected = false;
|
||
}
|
||
}
|
||
|
||
// 5. 创建海康相机重连定时器
|
||
m_pHikReconnectTimer = new QTimer(this);
|
||
m_pHikReconnectTimer->setInterval(5000); // 5秒重试一次
|
||
connect(m_pHikReconnectTimer, &QTimer::timeout, this, &TunnelChannelPresenter::OnHikReconnectTimer);
|
||
|
||
// 如果海康相机未连接,启动重连定时器
|
||
if (m_pHikDevice && !m_bHikConnected) {
|
||
m_pHikReconnectTimer->start();
|
||
LOG_INFO("Hik camera reconnect timer started (interval: 5000ms)\n");
|
||
}
|
||
|
||
// 6. 更新工作状态
|
||
CheckAndUpdateWorkStatus();
|
||
|
||
LOG_INFO("TunnelChannelPresenter::InitApp() - Initialization completed\n");
|
||
return SUCCESS;
|
||
}
|
||
|
||
int TunnelChannelPresenter::InitAlgoParams()
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::InitAlgoParams()\n");
|
||
|
||
// 算法暂时留空
|
||
// TODO: 加载隧道检测算法参数
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
int TunnelChannelPresenter::ProcessAlgoDetection(
|
||
std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& detectionDataCache)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::ProcessAlgoDetection() - Processing %zu data items\n",
|
||
detectionDataCache.size());
|
||
|
||
if (detectionDataCache.empty()) {
|
||
LOG_WARN("Detection data cache is empty\n");
|
||
return ERR_CODE(DEV_RESULT_EMPTY);
|
||
}
|
||
|
||
// 创建检测结果
|
||
TunnelDetectionResult result;
|
||
result.cameraIndex = m_currentCameraIndex;
|
||
result.errorCode = 0; // 0表示成功
|
||
|
||
// ========== 算法处理(暂时留空) ==========
|
||
// TODO: 实现隧道通道检测算法
|
||
// 1. 从点云数据中提取特征
|
||
// 2. 进行隧道轮廓检测
|
||
// 3. 计算检测结果
|
||
|
||
// 暂时使用点云生成深度图作为检测结果
|
||
QImage depthImage;
|
||
int imageResult = PointCloudImageUtils::GenerateDepthImage(detectionDataCache, depthImage);
|
||
if (imageResult == 0 && !depthImage.isNull()) {
|
||
result.image = depthImage;
|
||
} else {
|
||
LOG_WARN("Failed to generate depth image\n");
|
||
}
|
||
|
||
// 获取海康相机当前帧
|
||
result.hikImage = GetCurrentHikFrame();
|
||
|
||
// 通知UI更新检测结果
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
pStatusCallback->OnDetectionResult(result);
|
||
}
|
||
|
||
LOG_INFO("TunnelChannelPresenter::ProcessAlgoDetection() - Detection completed\n");
|
||
return SUCCESS;
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnCameraStatusChanged(int cameraIndex, bool isConnected)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::OnCameraStatusChanged() - Camera %d: %s\n",
|
||
cameraIndex, isConnected ? "Connected" : "Disconnected");
|
||
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
if (cameraIndex == 1) {
|
||
pStatusCallback->OnCamera1StatusChanged(isConnected);
|
||
} else if (cameraIndex == 2) {
|
||
pStatusCallback->OnCamera2StatusChanged(isConnected);
|
||
}
|
||
}
|
||
|
||
CheckAndUpdateWorkStatus();
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnWorkStatusChanged(WorkStatus status)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::OnWorkStatusChanged() - Status: %s\n",
|
||
WorkStatusToString(status).c_str());
|
||
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
pStatusCallback->OnWorkStatusChanged(status);
|
||
}
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnCameraCountChanged(int count)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::OnCameraCountChanged() - Count: %d\n", count);
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnStatusUpdate(const std::string& statusMessage)
|
||
{
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
pStatusCallback->OnStatusUpdate(statusMessage);
|
||
}
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnConfigChanged(const ConfigResult& configResult)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::OnConfigChanged()\n");
|
||
// 配置变化处理
|
||
}
|
||
|
||
// ============ 海康相机相关实现 ============
|
||
|
||
int TunnelChannelPresenter::InitHikDevice()
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::InitHikDevice()\n");
|
||
|
||
// 创建海康设备对象
|
||
int result = IHikDevice::CreateObject(&m_pHikDevice);
|
||
if (result != 0 || !m_pHikDevice) {
|
||
LOG_ERR("Failed to create HikDevice object\n");
|
||
return ERR_CODE(DATA_ERR_MEM);
|
||
}
|
||
|
||
// 初始化海康SDK
|
||
result = m_pHikDevice->InitSDK();
|
||
if (result != 0) {
|
||
LOG_ERR("Failed to initialize HikDevice SDK, error: %d\n", result);
|
||
delete m_pHikDevice;
|
||
m_pHikDevice = nullptr;
|
||
return result;
|
||
}
|
||
|
||
// 设置帧数据回调
|
||
m_pHikDevice->SetDecodedFrameCallback(
|
||
[this](unsigned char* pRGBData, int dataSize, const HikFrameInfo& frameInfo, void* pUser) {
|
||
this->OnHikFrameReceived(pRGBData, dataSize, frameInfo);
|
||
},
|
||
this
|
||
);
|
||
|
||
// 设置状态回调
|
||
m_pHikDevice->SetStatusCallback(
|
||
[this](EHikDeviceStatus status, void* pUser) {
|
||
this->OnHikDeviceStatusChanged(status);
|
||
},
|
||
this
|
||
);
|
||
|
||
// 设置异常回调
|
||
m_pHikDevice->SetExceptionCallback(
|
||
[this](EHikExceptionType exceptionType, void* pUser) {
|
||
this->OnHikExceptionReceived(exceptionType);
|
||
},
|
||
this
|
||
);
|
||
|
||
LOG_INFO("TunnelChannelPresenter::InitHikDevice() - HikDevice initialized successfully\n");
|
||
return SUCCESS;
|
||
}
|
||
|
||
int TunnelChannelPresenter::ConnectHikCamera(const HikCameraConfig& config)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::ConnectHikCamera() - IP: %s, Port: %d\n", config.ip.c_str(), config.port);
|
||
|
||
if (!m_pHikDevice) {
|
||
LOG_ERR("HikDevice not initialized\n");
|
||
return ERR_CODE(DEV_NO_OPEN);
|
||
}
|
||
|
||
// 转换配置
|
||
HikDeviceConfig deviceConfig;
|
||
deviceConfig.ip = config.ip;
|
||
deviceConfig.port = config.port;
|
||
deviceConfig.username = config.username;
|
||
deviceConfig.password = config.password;
|
||
deviceConfig.channelNo = config.channelNo;
|
||
deviceConfig.streamType = config.streamType;
|
||
deviceConfig.enabled = config.enabled;
|
||
|
||
// 登录相机
|
||
int result = m_pHikDevice->Login(deviceConfig);
|
||
if (result != 0) {
|
||
if (result == ERR_CODE(DEV_UNACTIVATE)) {
|
||
LOG_ERR("2D相机未激活,请先激活设备后再连接 (IP: %s)\n", config.ip.c_str());
|
||
OnStatusUpdate("2D相机未激活,请先激活设备");
|
||
} else {
|
||
LOG_ERR("Failed to login Hik camera, error: %d \n", result);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
m_bHikConnected = true;
|
||
LOG_INFO("TunnelChannelPresenter::ConnectHikCamera() - Connected successfully\n");
|
||
return SUCCESS;
|
||
}
|
||
|
||
void TunnelChannelPresenter::DisconnectHikCamera()
|
||
{
|
||
if (m_pHikDevice) {
|
||
m_pHikDevice->StopPreview();
|
||
m_pHikDevice->Logout();
|
||
m_bHikConnected = false;
|
||
LOG_INFO("TunnelChannelPresenter::DisconnectHikCamera() - Disconnected\n");
|
||
}
|
||
}
|
||
|
||
int TunnelChannelPresenter::StartHikPreview()
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::StartHikPreview()\n");
|
||
|
||
if (!m_pHikDevice) {
|
||
LOG_ERR("HikDevice not initialized\n");
|
||
return ERR_CODE(DEV_NO_OPEN);
|
||
}
|
||
|
||
if (!m_pHikDevice->IsLoggedIn()) {
|
||
LOG_ERR("Hik camera not logged in\n");
|
||
return ERR_CODE(DEV_NO_OPEN);
|
||
}
|
||
|
||
int result = m_pHikDevice->StartPreview();
|
||
if (result != 0) {
|
||
LOG_ERR("Failed to start Hik preview, error: %d\n", result);
|
||
return result;
|
||
}
|
||
|
||
LOG_INFO("TunnelChannelPresenter::StartHikPreview() - Preview started\n");
|
||
return SUCCESS;
|
||
}
|
||
|
||
int TunnelChannelPresenter::StartHikPreviewEx(void* hWnd)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::StartHikPreviewEx() - hWnd: %p\n", hWnd);
|
||
|
||
if (!m_pHikDevice) {
|
||
LOG_ERR("HikDevice not initialized\n");
|
||
return ERR_CODE(DEV_NO_OPEN);
|
||
}
|
||
|
||
if (!m_pHikDevice->IsLoggedIn()) {
|
||
LOG_ERR("Hik camera not logged in\n");
|
||
return ERR_CODE(DEV_NO_OPEN);
|
||
}
|
||
|
||
int result = m_pHikDevice->StartPreviewEx(hWnd);
|
||
if (result != 0) {
|
||
LOG_ERR("Failed to start Hik preview (hardware), error: %d\n", result);
|
||
return result;
|
||
}
|
||
|
||
LOG_INFO("TunnelChannelPresenter::StartHikPreviewEx() - Hardware preview started\n");
|
||
return SUCCESS;
|
||
}
|
||
|
||
void TunnelChannelPresenter::StopHikPreview()
|
||
{
|
||
if (m_pHikDevice) {
|
||
m_pHikDevice->StopPreview();
|
||
LOG_INFO("TunnelChannelPresenter::StopHikPreview() - Preview stopped\n");
|
||
}
|
||
}
|
||
|
||
QImage TunnelChannelPresenter::GetCurrentHikFrame() const
|
||
{
|
||
std::lock_guard<std::mutex> lock(m_hikFrameMutex);
|
||
return m_currentHikFrame;
|
||
}
|
||
|
||
bool TunnelChannelPresenter::IsHikCameraConnected() const
|
||
{
|
||
return m_bHikConnected && m_pHikDevice && m_pHikDevice->IsLoggedIn();
|
||
}
|
||
|
||
// ============ 海康相机回调处理 ============
|
||
|
||
void TunnelChannelPresenter::OnHikFrameReceived(unsigned char* pRGBData, int dataSize,
|
||
const HikFrameInfo& frameInfo)
|
||
{
|
||
if (!pRGBData || dataSize <= 0) {
|
||
return;
|
||
}
|
||
|
||
// 帧率限制:避免过度刷新UI
|
||
auto now = std::chrono::steady_clock::now();
|
||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastHikFrameTime).count();
|
||
if (elapsed < HIK_FRAME_INTERVAL_MS) {
|
||
return; // 跳过此帧
|
||
}
|
||
m_lastHikFrameTime = now;
|
||
|
||
int width = frameInfo.width;
|
||
int height = frameInfo.height;
|
||
int bytesPerLine = width * 4; // RGB32 格式: 每像素4字节
|
||
|
||
// 优化: 使用外部数据构造临时QImage,然后一次性拷贝
|
||
// 避免多次memcpy,只进行一次深拷贝
|
||
QImage tempImage(pRGBData, width, height, bytesPerLine, QImage::Format_RGB32);
|
||
QImage image = tempImage.copy(); // 只进行一次深拷贝
|
||
|
||
// 更新当前帧(使用移动语义,避免不必要的拷贝)
|
||
{
|
||
std::lock_guard<std::mutex> lock(m_hikFrameMutex);
|
||
m_currentHikFrame = std::move(image);
|
||
}
|
||
|
||
// 通过信号通知UI更新(QImage隐式共享,不会实际拷贝)
|
||
emit sigHikImageUpdated(m_currentHikFrame);
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnHikDeviceStatusChanged(EHikDeviceStatus status)
|
||
{
|
||
LOG_INFO("TunnelChannelPresenter::OnHikDeviceStatusChanged() - Status: %d\n", static_cast<int>(status));
|
||
|
||
// 通过信号转发到主线程处理(跨线程安全)
|
||
emit sigHikStatusChanged(static_cast<int>(status));
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnHikExceptionReceived(EHikExceptionType exceptionType)
|
||
{
|
||
LOG_WARN("TunnelChannelPresenter::OnHikExceptionReceived() - Exception: %d\n",
|
||
static_cast<int>(exceptionType));
|
||
|
||
// 通过信号转发到主线程处理(跨线程安全)
|
||
emit sigHikException(static_cast<int>(exceptionType));
|
||
}
|
||
|
||
void TunnelChannelPresenter::OnHikReconnectTimer()
|
||
{
|
||
if (m_bHikConnected) {
|
||
return; // 已连接,不需要重连
|
||
}
|
||
|
||
LOG_INFO("TunnelChannelPresenter::OnHikReconnectTimer() - Attempting to reconnect Hik camera\n");
|
||
|
||
ConfigResult config = m_pConfigManager->GetCurrentConfig();
|
||
if (config.hikCameraList.empty()) {
|
||
return;
|
||
}
|
||
|
||
const HikCameraConfig& hikConfig = config.hikCameraList[0];
|
||
if (!hikConfig.enabled) {
|
||
return;
|
||
}
|
||
|
||
// 尝试重新连接
|
||
int result = ConnectHikCamera(hikConfig);
|
||
if (result == 0) {
|
||
m_bHikConnected = true;
|
||
NotifyHikCameraStatus(true);
|
||
m_pHikReconnectTimer->stop();
|
||
|
||
// 关闭OSD显示(通道名称和时间)
|
||
m_pHikDevice->ConfigureOSD(false, false);
|
||
|
||
// 重新开始预览(根据是否设置窗口句柄选择渲染方式)
|
||
if (m_hHikDisplayWnd) {
|
||
StartHikPreviewEx(m_hHikDisplayWnd);
|
||
} else {
|
||
StartHikPreview();
|
||
}
|
||
}
|
||
}
|
||
|
||
void TunnelChannelPresenter::CheckAndUpdateWorkStatus()
|
||
{
|
||
bool hasCameraConnected = m_bCameraConnected || m_bHikConnected;
|
||
|
||
if (hasCameraConnected) {
|
||
SetWorkStatus(WorkStatus::Ready);
|
||
} else {
|
||
// 如果没有任何相机连接,保持初始化状态
|
||
if (GetCurrentWorkStatus() != WorkStatus::InitIng) {
|
||
SetWorkStatus(WorkStatus::Ready);
|
||
}
|
||
}
|
||
}
|
||
|
||
void TunnelChannelPresenter::NotifyHikCameraStatus(bool isConnected)
|
||
{
|
||
// 2D海康相机使用相机2的状态更新接口
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
pStatusCallback->OnCamera2StatusChanged(isConnected);
|
||
}
|
||
}
|
||
|
||
void TunnelChannelPresenter::NotifyRobotConnectionStatus(bool isConnected)
|
||
{
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
pStatusCallback->OnRobotConnectionChanged(isConnected);
|
||
}
|
||
}
|
||
|
||
void TunnelChannelPresenter::NotifySerialConnectionStatus(bool isConnected)
|
||
{
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
pStatusCallback->OnSerialConnectionChanged(isConnected);
|
||
}
|
||
}
|
||
|
||
// ============ 相机调平接口实现 ============
|
||
|
||
bool TunnelChannelPresenter::CalculatePlaneCalibration(
|
||
const std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& scanData,
|
||
double planeCalib[9],
|
||
double& planeHeight,
|
||
double invRMatrix[9])
|
||
{
|
||
// TODO: 实现平面调平计算
|
||
// 暂时返回单位矩阵
|
||
for (int i = 0; i < 9; i++) {
|
||
planeCalib[i] = (i % 4 == 0) ? 1.0 : 0.0;
|
||
invRMatrix[i] = (i % 4 == 0) ? 1.0 : 0.0;
|
||
}
|
||
planeHeight = 0.0;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool TunnelChannelPresenter::SaveLevelingResults(
|
||
double planeCalib[9], double planeHeight, double invRMatrix[9],
|
||
int cameraIndex, const QString& cameraName)
|
||
{
|
||
// TODO: 保存调平结果到配置文件
|
||
LOG_INFO("SaveLevelingResults for camera %d (%s)\n",
|
||
cameraIndex, cameraName.toStdString().c_str());
|
||
return true;
|
||
}
|
||
|
||
bool TunnelChannelPresenter::LoadLevelingResults(
|
||
int cameraIndex, const QString& cameraName,
|
||
double planeCalib[9], double& planeHeight, double invRMatrix[9])
|
||
{
|
||
// TODO: 从配置文件加载调平结果
|
||
LOG_INFO("LoadLevelingResults for camera %d (%s)\n",
|
||
cameraIndex, cameraName.toStdString().c_str());
|
||
|
||
// 默认返回单位矩阵
|
||
for (int i = 0; i < 9; i++) {
|
||
planeCalib[i] = (i % 4 == 0) ? 1.0 : 0.0;
|
||
invRMatrix[i] = (i % 4 == 0) ? 1.0 : 0.0;
|
||
}
|
||
planeHeight = 0.0;
|
||
|
||
return true;
|
||
}
|
||
|
||
// ============ 跨线程槽函数实现(在主线程执行) ============
|
||
|
||
void TunnelChannelPresenter::onHikImageUpdatedInMainThread(const QImage& image)
|
||
{
|
||
// 通知UI更新(在主线程中安全调用)
|
||
auto* pStatusCallback = GetStatusCallback<IYTunnelChannelStatus>();
|
||
if (pStatusCallback) {
|
||
pStatusCallback->OnHikImageUpdated(image);
|
||
}
|
||
}
|
||
|
||
void TunnelChannelPresenter::onHikStatusChangedInMainThread(int status)
|
||
{
|
||
EHikDeviceStatus hikStatus = static_cast<EHikDeviceStatus>(status);
|
||
|
||
switch (hikStatus) {
|
||
case EHikDeviceStatus::Connected:
|
||
m_bHikConnected = true;
|
||
NotifyHikCameraStatus(true);
|
||
break;
|
||
|
||
case EHikDeviceStatus::Disconnected:
|
||
case EHikDeviceStatus::Error:
|
||
m_bHikConnected = false;
|
||
NotifyHikCameraStatus(false);
|
||
|
||
// 启动重连定时器(在主线程中直接操作QTimer)
|
||
if (m_pHikReconnectTimer && !m_pHikReconnectTimer->isActive()) {
|
||
m_pHikReconnectTimer->start();
|
||
LOG_INFO("Hik camera reconnect timer started due to status change\n");
|
||
}
|
||
break;
|
||
|
||
case EHikDeviceStatus::Reconnecting:
|
||
LOG_INFO("Hik camera is reconnecting...\n");
|
||
break;
|
||
|
||
case EHikDeviceStatus::Previewing:
|
||
LOG_INFO("Hik camera is previewing\n");
|
||
break;
|
||
}
|
||
|
||
CheckAndUpdateWorkStatus();
|
||
}
|
||
|
||
void TunnelChannelPresenter::onHikExceptionInMainThread(int exceptionType)
|
||
{
|
||
EHikExceptionType hikException = static_cast<EHikExceptionType>(exceptionType);
|
||
|
||
switch (hikException) {
|
||
case EHikExceptionType::PreviewException:
|
||
// 预览异常,停止预览
|
||
StopHikPreview();
|
||
m_bHikConnected = false;
|
||
NotifyHikCameraStatus(false);
|
||
|
||
// 启动重连定时器(在主线程中直接操作QTimer)
|
||
if (m_pHikReconnectTimer && !m_pHikReconnectTimer->isActive()) {
|
||
m_pHikReconnectTimer->start();
|
||
LOG_INFO("Hik camera reconnect timer started due to exception\n");
|
||
}
|
||
break;
|
||
|
||
case EHikExceptionType::Reconnect:
|
||
LOG_INFO("Hik camera preview reconnecting...\n");
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|