#ifndef POINT_CLOUD_CONVERTER_H #define POINT_CLOUD_CONVERTER_H #include #include #include #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 fields; std::vector fieldSizes; std::vector 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 properties; }; /** * @brief PLY 文件头 */ struct PlyHeader { enum Format { ASCII, BINARY_LE, BINARY_BE }; Format format = ASCII; std::vector 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