在 CAM 套料软件中通过 C++ 实现工程文件的序列化操作(包含点、直线、圆、圆弧等几何信息),可以按照以下步骤进行架构和实现:
1. 定义几何数据结构
首先需要为每种几何元素定义对应的数据结构:
// 基础点结构
struct Point {
double x;
double y;
};
// 直线(两点确定一条直线)
struct Line {
Point start;
Point end;
};
// 圆(圆心和半径)
struct Circle {
Point center;
double radius;
};
// 圆弧(圆心、半径、起始角、终止角、方向)
struct Arc {
Point center;
double radius;
double start_angle; // 弧度
double end_angle; // 弧度
bool clockwise; // 方向
};
2. 工程文件结构设计
工程文件需要包含几何数据集合和可能的元信息:
#include <vector>
#include <string>
struct Project {
std::string version; // 工程版本
std::vector<Point> points; // 点集合
std::vector<Line> lines; // 直线集合
std::vector<Circle> circles; // 圆集合
std::vector<Arc> arcs; // 圆弧集合
};
3. 序列化方法选择
序列化可以选择二进制、XML、JSON 或自定义文本格式。这里以 二进制序列化 为例:
二进制序列化优点
- 紧凑高效,适合大规模几何数据
- 读写速度快
- 直接映射内存结构,实现简单
实现工具
- 直接使用
std::ofstream
和std::ifstream
进行二进制读写 - 或使用 Boost.Serialization 库
4. 实现序列化与反序列化
基础类型的序列化函数
#include <fstream>
#include <vector>
// 序列化基础类型(如 double、bool 等)
template <typename T>
void serialize(std::ofstream& out, const T& value) {
out.write(reinterpret_cast<const char*>(&value), sizeof(T));
}
// 反序列化基础类型
template <typename T>
void deserialize(std::ifstream& in, T& value) {
in.read(reinterpret_cast<char*>(&value), sizeof(T));
}
// 序列化字符串
void serialize(std::ofstream& out, const std::string& str) {
size_t size = str.size();
serialize(out, size);
out.write(str.c_str(), size);
}
// 反序列化字符串
void deserialize(std::ifstream& in, std::string& str) {
size_t size;
deserialize(in, size);
str.resize(size);
in.read(&str[0], size);
}
// 序列化向量容器
template <typename T>
void serialize(std::ofstream& out, const std::vector<T>& vec) {
size_t size = vec.size();
serialize(out, size);
for (const auto& item : vec) {
serialize(out, item); // 需要为 T 实现 serialize
}
}
// 反序列化向量容器
template <typename T>
void deserialize(std::ifstream& in, std::vector<T>& vec) {
size_t size;
deserialize(in, size);
vec.resize(size);
for (auto& item : vec) {
deserialize(in, item); // 需要为 T 实现 deserialize
}
}
几何结构的具体序列化
// Point 的序列化
void serialize(std::ofstream& out, const Point& p) {
serialize(out, p.x);
serialize(out, p.y);
}
void deserialize(std::ifstream& in, Point& p) {
deserialize(in, p.x);
deserialize(in, p.y);
}
// Line 的序列化
void serialize(std::ofstream& out, const Line& line) {
serialize(out, line.start);
serialize(out, line.end);
}
void deserialize(std::ifstream& in, Line& line) {
deserialize(in, line.start);
deserialize(in, line.end);
}
// Circle 的序列化
void serialize(std::ofstream& out, const Circle& circle) {
serialize(out, circle.center);
serialize(out, circle.radius);
}
void deserialize(std::ifstream& in, Circle& circle) {
deserialize(in, circle.center);
deserialize(in, circle.radius);
}
// Arc 的序列化
void serialize(std::ofstream& out, const Arc& arc) {
serialize(out, arc.center);
serialize(out, arc.radius);
serialize(out, arc.start_angle);
serialize(out, arc.end_angle);
serialize(out, arc.clockwise);
}
void deserialize(std::ifstream& in, Arc& arc) {
deserialize(in, arc.center);
deserialize(in, arc.radius);
deserialize(in, arc.start_angle);
deserialize(in, arc.end_angle);
deserialize(in, arc.clockwise);
}
Project 类的序列化
void serialize(std::ofstream& out, const Project& project) {
serialize(out, project.version);
serialize(out, project.points);
serialize(out, project.lines);
serialize(out, project.circles);
serialize(out, project.arcs);
}
void deserialize(std::ifstream& in, Project& project) {
deserialize(in, project.version);
deserialize(in, project.points);
deserialize(in, project.lines);
deserialize(in, project.circles);
deserialize(in, project.arcs);
}
5. 保存和加载工程文件
// 保存工程到文件
bool saveProject(const std::string& filename, const Project& project) {
std::ofstream out(filename, std::ios::binary);
if (!out.is_open()) return false;
serialize(out, project);
return true;
}
// 从文件加载工程
bool loadProject(const std::string& filename, Project& project) {
std::ifstream in(filename, std::ios::binary);
if (!in.is_open()) return false;
deserialize(in, project);
return true;
}
6. 高级优化建议
版本兼容性
在文件头添加版本号,确保向后兼容:
struct Project {
uint32_t version_major = 1;
uint32_t version_minor = 0;
// ...其他字段
};
错误处理
- 检查文件读写是否成功
- 添加校验和(如 CRC32)验证数据完整性
性能优化
- 使用内存映射文件处理大规模数据
- 压缩数据(如 zlib)
多态支持
如果需要继承(例如 Shape
基类),需额外存储类型信息:
enum class ShapeType { Point, Line, Circle, Arc };
struct Shape {
virtual void serialize(std::ofstream& out) const = 0;
virtual void deserialize(std::ifstream& in) = 0;
virtual ~Shape() = default;
};
// 序列化时先写入类型标识符
void serializeShape(std::ofstream& out, const Shape& shape) {
if (auto p = dynamic_cast<const Point*>(&shape)) {
serialize(out, ShapeType::Point);
serialize(out, *p);
} // 类似处理其他类型
}
7. 示例使用
int main() {
Project project;
project.version = "1.0";
project.points.push_back({0.0, 0.0});
project.lines.push_back({{1.0, 1.0}, {2.0, 2.0}});
project.circles.push_back({{3.0, 3.0}, 5.0});
project.arcs.push_back({{4.0, 4.0}, 2.0, 0.0, 3.14, true});
// 保存工程
saveProject("test.cam", project);
// 加载工程
Project loaded_project;
loadProject("test.cam", loaded_project);
return 0;
}
关键注意事项
- 字节序(Endianness):如果跨平台使用,需处理大小端问题。
- 数据对齐:确保结构体在序列化时无填充字节。
- 异常处理:在读写失败时提供清晰的错误信息。