170 lines
5.2 KiB
C++
170 lines
5.2 KiB
C++
#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
|