Utils/CloudView/Inc/PointCloudConverter.h

150 lines
4.2 KiB
C
Raw Normal View History

2026-02-19 00:45:00 +08:00
#ifndef POINT_CLOUD_CONVERTER_H
#define POINT_CLOUD_CONVERTER_H
#include <string>
#include <vector>
#include <memory>
/**
* @brief 简单的 3D 点结构
*/
struct Point3D
{
float x, y, z;
Point3D() : x(0), y(0), z(0) {}
Point3D(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
};
/**
* @brief 带颜色的 3D 点结构
*/
struct Point3DRGB
{
float x, y, z;
uint8_t r, g, b;
Point3DRGB() : x(0), y(0), z(0), r(255), g(255), b(255) {}
Point3DRGB(float _x, float _y, float _z, uint8_t _r = 255, uint8_t _g = 255, uint8_t _b = 255)
: x(_x), y(_y), z(_z), r(_r), g(_g), b(_b) {}
};
/**
* @brief 简单的点云容器
*/
template<typename PointT>
class SimplePointCloud
{
public:
std::vector<PointT> points;
std::vector<int> lineIndices; // 每个点所属的线索引
void clear() { points.clear(); lineIndices.clear(); }
size_t size() const { return points.size(); }
bool empty() const { return points.empty(); }
void reserve(size_t n) { points.reserve(n); lineIndices.reserve(n); }
void push_back(const PointT& pt) { points.push_back(pt); }
void push_back(const PointT& pt, int lineIdx) {
points.push_back(pt);
lineIndices.push_back(lineIdx);
}
};
using PointCloudXYZ = SimplePointCloud<Point3D>;
using PointCloudXYZRGB = SimplePointCloud<Point3DRGB>;
/**
* @brief 点云数据转换器
* 负责加载 txt 和 pcd 格式的点云文件
*/
class PointCloudConverter
{
public:
PointCloudConverter();
~PointCloudConverter();
/**
* @brief 从 txt 文件加载点云(使用 CloudUtils)
*/
int loadFromTxt(const std::string& fileName, PointCloudXYZ& cloud);
int loadFromTxt(const std::string& fileName, PointCloudXYZRGB& cloud);
/**
* @brief 从 pcd 文件加载点云(简单 ASCII/Binary 解析)
*/
int loadFromPcd(const std::string& fileName, PointCloudXYZ& cloud);
int loadFromPcd(const std::string& fileName, PointCloudXYZRGB& cloud);
/**
* @brief 根据文件扩展名自动选择加载方式
*/
int loadFromFile(const std::string& fileName, PointCloudXYZ& cloud);
int loadFromFile(const std::string& fileName, PointCloudXYZRGB& cloud);
/**
* @brief 保存点云到 txt 文件(使用 CloudUtils)
*/
int saveToTxt(const std::string& fileName, const PointCloudXYZ& cloud, int lineNum, int linePtNum);
/**
* @brief 旋转点云(行列转置 + 交换XY)
* @param cloud 输入点云
* @param rotatedCloud 输出旋转后的点云
* @param lineNum 原始线数
* @param linePtNum 原始每线点数
* @param newLineNum 输出新的线数
* @param newLinePtNum 输出新的每线点数
*/
int rotateCloud(const PointCloudXYZ& cloud, PointCloudXYZ& rotatedCloud,
int lineNum, int linePtNum, int& newLineNum, int& newLinePtNum);
/**
* @brief 获取最后的错误信息
*/
std::string getLastError() const { return m_lastError; }
/**
* @brief 获取加载的点云数量
*/
size_t getLoadedPointCount() const { return m_loadedPointCount; }
/**
* @brief 获取加载的线数量
*/
int getLoadedLineCount() const { return m_loadedLineCount; }
/**
* @brief 上次 loadFromTxt(PointCloudXYZRGB&) 加载的文件是否包含颜色数据
*/
bool lastLoadHadColor() const { return m_lastLoadHadColor; }
private:
/**
* @brief 获取文件扩展名(小写)
*/
std::string getFileExtension(const std::string& fileName);
/**
* @brief 解析 PCD 文件头
*/
struct PcdHeader
{
int width = 0;
int height = 1;
int points = 0;
bool isBinary = false;
bool hasRgb = false;
std::vector<std::string> fields;
std::vector<int> fieldSizes;
std::vector<char> fieldTypes;
int pointSize = 0;
};
bool parsePcdHeader(std::ifstream& file, PcdHeader& header);
std::string m_lastError;
size_t m_loadedPointCount;
int m_loadedLineCount;
bool m_lastLoadHadColor;
};
#endif // POINT_CLOUD_CONVERTER_H