Utils/CloudView/Inc/PointCloudConverter.h
2026-07-13 18:56:01 +08:00

170 lines
5.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef POINT_CLOUD_CONVERTER_H
#define POINT_CLOUD_CONVERTER_H
#include <string>
#include <vector>
#include <memory>
#include "CloudView3DTypes.h"
/**
* @brief 点云数据转换器
* 负责加载 txt/dat、pcd、ply 格式的点云文件
*/
class PointCloudConverter
{
public:
PointCloudConverter();
~PointCloudConverter();
/**
* @brief 从 txt/dat 文件加载点云(使用 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 从 ply 文件加载点云(支持 ASCII / Binary Little-Endian / Binary Big-Endian
*/
int loadFromPly(const std::string& fileName, PointCloudXYZ& cloud);
int loadFromPly(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 保存点云到 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);
/**
* @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);
std::string m_lastError;
size_t m_loadedPointCount;
int m_loadedLineCount;
bool m_lastLoadHadColor;
};
#endif // POINT_CLOUD_CONVERTER_H