Utils/CloudView/Inc/PointCloudConverter.h

170 lines
5.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
2026-07-13 18:56:01 +08:00
#include <string>
#include <vector>
#include <memory>
#include "CloudView3DTypes.h"
/**
* @brief 点云数据转换器
2026-07-03 12:46:19 +08:00
* 负责加载 txt/dat、pcd、ply 格式的点云文件
2026-02-19 00:45:00 +08:00
*/
class PointCloudConverter
{
public:
PointCloudConverter();
~PointCloudConverter();
/**
2026-07-03 12:46:19 +08:00
* @brief 从 txt/dat 文件加载点云(使用 CloudUtils)
2026-02-19 00:45:00 +08:00
*/
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 从 ply 文件加载点云(支持 ASCII / Binary Little-Endian / Binary Big-Endian)
*/
int loadFromPly(const std::string& fileName, PointCloudXYZ& cloud);
int loadFromPly(const std::string& fileName, PointCloudXYZRGB& cloud);
2026-02-19 00:45:00 +08:00
/**
* @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 保存点云到 PLY 文件(ASCII 格式)
* @param fileName 输出文件路径
* @param cloud 点云数据
* @return 0=成功, -1=失败
*/
int saveToPly(const std::string& fileName, const PointCloudXYZ& cloud);
/**
* @brief 保存点云到 PCD 文件(ASCII 格式,兼容 PCL)
* @param fileName 输出文件路径
* @param cloud 点云数据
* @return 0=成功, -1=失败
*/
int saveToPcd(const std::string& fileName, const PointCloudXYZ& cloud);
2026-02-19 00:45:00 +08:00
/**
* @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);
/**
* @brief PLY 属性描述
*/
struct PlyProperty
{
std::string name; // 属性名 (x, y, z, red, green, blue, alpha, nx, ny, nz ...)
std::string type; // 数据类型 (float, double, uchar, int, short ...)
int byteSize = 0; // 字节数
bool isList = false; // 是否是 list 类型(如 face 的 vertex_indices)
std::string listCountType; // list 的计数类型
std::string listValueType; // list 的值类型
};
/**
* @brief PLY 元素描述
*/
struct PlyElement
{
std::string name; // 元素名 (vertex, face ...)
int count = 0; // 元素数量
std::vector<PlyProperty> properties;
};
/**
* @brief PLY 文件头
*/
struct PlyHeader
{
enum Format { ASCII, BINARY_LE, BINARY_BE };
Format format = ASCII;
std::vector<PlyElement> elements;
int vertexElementIndex = -1; // vertex 元素在 elements 中的索引
};
bool parsePlyHeader(std::ifstream& file, PlyHeader& header);
int getPlyTypeByteSize(const std::string& type);
/**
* @brief 计算 PLY 元素中一个非 list 记录的总字节数
*/
int calcPlyElementStride(const PlyElement& element);
2026-02-19 00:45:00 +08:00
std::string m_lastError;
size_t m_loadedPointCount;
int m_loadedLineCount;
bool m_lastLoadHadColor;
};
#endif // POINT_CLOUD_CONVERTER_H