125 lines
4.3 KiB
C
Raw Normal View History

#ifndef CCLOUDSHOW_H
#define CCLOUDSHOW_H
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <vtkTextActor.h>
#include <atomic>
#include <condition_variable>
#include <deque>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include "ICloudShow.h"
class vtkOrientationMarkerWidget;
class CCloudShow : public ICloudShow
{
public:
CCloudShow();
~CCloudShow() override;
int Show(const CloudData& cloudData,
const CloudFrameInfo& info,
const std::string& windowName = "PointCloud") override;
int Start(const std::string& windowName = "PointCloud", void* hwnd = nullptr) override;
int Stop() override;
int SpinOnce(int ms = 1) override;
bool IsRunning() const override;
void PushFrame(const CloudData& cloudData,
const CloudFrameInfo& info) override;
void SetSaveBaseDir(const std::string& dir) override;
void SetSaveFrameInterval(int interval) override;
bool IsSaveActive() const override;
bool IsQuitRequested() const override;
bool IsSaveRequested() const override;
void ClearSaveRequest() override;
private:
static void keyboardCallback(const pcl::visualization::KeyboardEvent& event, void* cookie);
// UI
void handleStartStopToggle();
void updateStartStopButton();
void updateProgressText();
// 保存线程
void saveLoop();
// ── 显示相关 ──
std::shared_ptr<pcl::visualization::PCLVisualizer> m_viewer;
std::atomic<bool> m_bRunning{false};
std::mutex m_cloudMutex;
bool m_bUpdated = false;
bool m_bFirstCloud = true;
std::string m_windowName;
vtkOrientationMarkerWidget* m_axesWidget = nullptr;
// 当前待显示的 PCL 云 + 最近一帧 CloudData供单帧保存
// 注意m_lastCloudData / m_lastCloudBuffers / m_lastFrameInfo 被 PushFrame回调线程
// 和 SpinOnce主线程同时访问需 m_lastCloudMutex 保护
pcl::PointCloud<pcl::PointXYZI>::Ptr m_displayCloud;
pcl::PointCloud<pcl::PointXYZI>::Ptr m_renderPool; // 复用,避免每帧 make_shared
std::mutex m_lastCloudMutex;
CloudData m_lastCloudData;
CloudFrameInfo m_lastFrameInfo;
std::vector<std::vector<uint8_t>> m_lastCloudBuffers;
// UI 状态
std::atomic<bool> m_bQuitRequested{false};
std::atomic<bool> m_bSaveRequested{false};
std::atomic<bool> m_bStartStopRequested{false};
vtkTextActor* m_pStartStopBtnActor = nullptr;
vtkTextActor* m_pProgressActor = nullptr;
std::mutex m_textMutex;
// ── 保存相关 ──
struct SaveTask
{
CloudData cloudData; // 深拷贝的标准格式
std::vector<std::vector<uint8_t>> buffers; // p3DPoint 指向的实际内存(预分配复用)
CloudFrameInfo info;
};
std::string m_saveBaseDir = ".";
std::atomic<bool> m_bSaveActive{false};
std::string m_currentSessionDir;
// SaveTask 缓冲池PushFrame回调线程从池取预分配好的 task
// 零堆分配完成数据拷贝saveLoop 用完后归还。消除回调线程的 malloc 延迟抖动。
std::mutex m_taskPoolMutex;
std::vector<SaveTask> m_taskPool; // 空闲 task 栈
SaveTask acquireTask();
void releaseTask(SaveTask& task);
void packIntoTask(SaveTask& task,
const ICloudShow::CloudData& cloudData,
const CloudFrameInfo& info);
std::mutex m_saveMutex;
std::condition_variable m_saveCv;
std::deque<SaveTask> m_saveQueue;
std::atomic<bool> m_bFlushAndSave{false}; // true=STOP已点击保存线程开始写盘
static constexpr int SAVE_THREAD_COUNT = 1;
std::atomic<bool> m_saveExit{false};
std::vector<std::thread> m_saveThreads;
std::atomic<int> m_nSaveSeq{0};
std::atomic<int> m_nSingleSaveSeq{0};
std::atomic<int> m_nSaveDropped{0};
std::atomic<int> m_saveCompleted{0};
std::atomic<int> m_saveTotal{0};
int m_nSaveFrameInterval = 10; // 保存帧间隔默认每10帧存1帧
int m_nPushFrameCount = 0; // PushFrame 调用计数(回调线程独占)
};
#endif // CCLOUDSHOW_H