源码架构分析
第14章 源码架构分析
14.1 项目结构
14.1.1 目录结构
solvespace/
├── CMakeLists.txt # 主CMake配置
├── CHANGELOG.md # 版本历史
├── CONTRIBUTING.md # 贡献指南
├── LICENSE.txt # GPL v3许可证
├── README.md # 项目说明
│
├── src/ # 主要源代码
│ ├── CMakeLists.txt
│ ├── solvespace.h # 主头文件
│ ├── solvespace.cpp # 主程序入口
│ │
│ ├── sketch.h # 草图数据结构
│ ├── dsc.h # 数据结构和容器
│ ├── polygon.h # 多边形处理
│ ├── expr.h # 表达式系统
│ ├── ui.h # 用户界面
│ │
│ ├── platform/ # 平台相关代码
│ │ ├── platform.h
│ │ ├── gui*.cpp # GUI实现
│ │ └── ...
│ │
│ ├── render/ # 渲染系统
│ │ └── ...
│ │
│ ├── srf/ # 曲面处理
│ │ └── ...
│ │
│ └── slvs/ # 约束求解器
│ └── ...
│
├── include/ # 公共头文件
│ └── slvs.h # 库API头文件
│
├── exposed/ # 库文档和示例
│ ├── DOC.txt
│ ├── CDemo.c
│ └── VbDemo.vb
│
├── python/ # Python绑定
│ ├── slvs/
│ └── tests/
│
├── test/ # 测试文件
│ └── ...
│
├── res/ # 资源文件
│ ├── icons/
│ ├── fonts/
│ └── locales/
│
├── extlib/ # 第三方库(子模块)
│ ├── eigen/ # 线性代数
│ ├── libdxfrw/ # DXF读写
│ ├── mimalloc/ # 内存分配
│ └── q3d/ # OpenGL支持
│
└── developer_docs/ # 开发者文档
├── IdLists_Entities_and_Remap.txt
└── Solver_Transforms.txt
14.1.2 模块划分
核心模块:
├── 约束求解器 (system.cpp, expr.cpp)
├── 几何核心 (entity.cpp, constraint.cpp)
├── 实体生成 (generate.cpp, group.cpp)
├── 网格处理 (mesh.cpp, bsp.cpp, polygon.cpp)
└── 曲面处理 (srf/*.cpp)
用户界面:
├── 图形窗口 (graphicswin.cpp, draw.cpp)
├── 属性浏览器 (textwin.cpp, textscreens.cpp)
├── 工具栏 (toolbar.cpp)
└── 鼠标交互 (mouse.cpp)
文件处理:
├── 文件读写 (file.cpp)
├── 导入 (importdxf.cpp, importmesh.cpp, importidf.cpp)
└── 导出 (export.cpp, exportstep.cpp, exportvector.cpp)
平台层:
└── platform/*.cpp (Windows/macOS/Linux/Web)
14.2 核心数据结构
14.2.1 句柄系统
SolveSpace使用句柄(Handle)代替指针引用对象:
// src/handle.h
template<typename T>
class Handle {
public:
uint32_t v;
bool operator==(const Handle<T> &rhs) const {
return v == rhs.v;
}
uint32_t IsReq() { return v & 0x80000000; }
};
typedef Handle<EntityBase> hEntity;
typedef Handle<ConstraintBase> hConstraint;
typedef Handle<GroupBase> hGroup;
typedef Handle<ParamBase> hParam;
优点
- 避免悬空指针
- 便于序列化
- 支持ID查找
14.2.2 IdList容器
IdList是SolveSpace的核心容器:
// src/dsc.h
template<class T, class H>
class IdList {
T *elem; // 元素数组
int n; // 元素数量
int elemsAllocated;
public:
T *FindById(H h); // O(log n) 二分查找
T *FindByIdNoOops(H h);
void Add(T *t); // O(n) 保持排序
void Remove(H h);
void Clear();
// STL兼容迭代器
class iterator { ... };
iterator begin();
iterator end();
};
特点
- 按ID排序存储
- 二分查找 O(log n)
- 插入 O(n)(需要移动元素)
14.2.3 实体结构
// src/sketch.h
class EntityBase {
public:
enum class Type : uint32_t {
POINT_IN_3D = 2000,
POINT_IN_2D = 2001,
POINT_N_TRANS = 2010,
POINT_N_ROT_TRANS = 2011,
// ... 更多类型
NORMAL_IN_3D = 3000,
NORMAL_IN_2D = 3001,
// ...
LINE_SEGMENT = 11000,
CIRCLE = 12000,
ARC_OF_CIRCLE = 13000,
CUBIC = 14000,
// ...
};
hEntity h;
hGroup group;
Type type;
hEntity workplane;
hEntity point[4]; // 点引用
hEntity normal; // 法线引用
hEntity distance; // 距离引用
hParam param[8]; // 参数引用
// 几何方法
Vector PointGetNum();
ExprVector PointGetExprs();
void PointForceTo(Vector v);
// ...
};
14.2.4 约束结构
// src/sketch.h
class ConstraintBase {
public:
enum class Type : uint32_t {
POINTS_COINCIDENT = 20,
PT_PT_DISTANCE = 30,
PT_LINE_DISTANCE = 31,
HORIZONTAL = 80,
VERTICAL = 81,
// ... 更多类型
};
hConstraint h;
hGroup group;
Type type;
hEntity workplane;
double valA; // 约束值
hEntity ptA, ptB; // 点引用
hEntity entityA, entityB; // 实体引用
bool other; // 附加标志
bool reference; // 是否为参考约束
// 生成方程
void GenerateEquations(IdList<Equation> *l);
};
14.2.5 组结构
// src/sketch.h
class GroupBase {
public:
enum class Type : uint32_t {
DRAWING_3D,
DRAWING_WORKPLANE,
EXTRUDE,
LATHE,
REVOLVE,
HELIX,
TRANSLATE,
ROTATE,
LINKED,
};
hGroup h;
Type type;
hGroup opA; // 操作源组
// 几何数据
IdList<EntityMap> remap;
// 实体模型
SShell thisShell;
SMesh thisMesh;
// 生成函数
void Generate(IdList<Entity> *entity,
IdList<Param> *param);
};
14.3 表达式系统
14.3.1 Expr类
表达式是约束系统的核心:
// src/expr.h
class Expr {
public:
enum {
// 常量和变量
CONSTANT = 0,
PARAM = 1,
// 二元运算
PLUS = 100,
MINUS = 101,
TIMES = 102,
DIV = 103,
// 函数
SIN = 200,
COS = 201,
ASIN = 202,
ACOS = 203,
SQRT = 204,
SQUARE = 205,
NEGATE = 300,
};
int op;
double v; // CONSTANT的值
hParam parh; // PARAM的句柄
Expr *a, *b; // 操作数
// 求值和微分
double Eval();
Expr *PartialWrt(hParam p);
// 简化
Expr *FoldConstants();
// 构造函数
static Expr *From(double v);
static Expr *From(hParam p);
Expr *Plus(Expr *b);
Expr *Minus(Expr *b);
Expr *Times(Expr *b);
// ...
};
14.3.2 ExprVector
向量表达式:
class ExprVector {
public:
Expr *x, *y, *z;
ExprVector Plus(ExprVector b);
ExprVector Minus(ExprVector b);
ExprVector Cross(ExprVector b);
Expr *Dot(ExprVector b);
Expr *Magnitude();
Vector Eval();
};
14.3.3 符号微分
// src/expr.cpp
Expr *Expr::PartialWrt(hParam p) {
switch(op) {
case CONSTANT:
return From(0.0);
case PARAM:
return From(parh == p ? 1.0 : 0.0);
case PLUS:
return a->PartialWrt(p)->Plus(b->PartialWrt(p));
case TIMES:
// 乘法法则: (ab)' = a'b + ab'
return a->PartialWrt(p)->Times(b)->Plus(
a->Times(b->PartialWrt(p)));
case SIN:
// sin'(f) = cos(f) * f'
return From(CONST_PI/180)->Times(
a->PartialWrt(p)->Times(
Expr::From(COS, a)));
// ...
}
}
14.4 约束求解器
14.4.1 System类
// src/system.h
class System {
public:
IdList<Param, hParam> param;
IdList<Equation, hEquation> eq;
int dof;
// 矩阵数据
struct {
Eigen::SparseMatrix<double> A;
Eigen::VectorXd B;
int n, m;
} mat;
// 求解方法
int Solve(Group *g, int *rank, bool andFindBad,
bool *redundant, bool *didnt_converge);
private:
void EvalJacobian();
bool NewtonSolve(int tag);
void WriteEquationsExceptFor(hConstraint hc,
IdList<Equation> *l);
};
14.4.2 求解流程
// src/system.cpp
int System::Solve(Group *g, ...) {
// 1. 生成方程
eq.Clear();
for(auto &c : SK.constraint) {
c.GenerateEquations(&eq);
}
// 2. 设置矩阵维度
mat.n = param.n; // 参数数量
mat.m = eq.n; // 方程数量
// 3. 牛顿迭代
for(int iter = 0; iter < MAX_ITER; iter++) {
// 计算雅可比矩阵
EvalJacobian();
// 检查收敛
if(converged()) {
return SOLVED_OKAY;
}
// 求解 J*Δx = -F
SolveLinear();
// 更新参数
UpdateParams();
}
return DIDNT_CONVERGE;
}
14.4.3 雅可比矩阵计算
void System::EvalJacobian() {
mat.A.setZero();
for(int i = 0; i < eq.n; i++) {
Equation *e = &(eq.elem[i]);
Expr *f = e->e;
// 方程值
mat.B[i] = f->Eval();
// 偏导数
for(int j = 0; j < param.n; j++) {
hParam p = param.elem[j].h;
Expr *pd = f->PartialWrt(p);
double v = pd->Eval();
if(fabs(v) > 1e-20) {
mat.A.insert(i, j) = v;
}
}
}
}
14.5 几何内核
14.5.1 网格处理 (SMesh)
// src/polygon.h
class SMesh {
public:
List<STriangle> l; // 三角形列表
void Clear();
void AddTriangle(STriangle *t);
void MakeFromCopy(SMesh *src);
// 布尔运算
void MakeFromUnion(SMesh *a, SMesh *b);
void MakeFromDifference(SMesh *a, SMesh *b);
void MakeFromIntersection(SMesh *a, SMesh *b);
// 网格修复
void RemoveDegenerates();
void FlipNormals();
};
14.5.2 曲面处理 (SShell)
// src/polygon.h
class SShell {
public:
IdList<SCurve> curve; // 曲线列表
IdList<SSurface> surface; // 曲面列表
// 布尔运算
void MakeFromExtrusion(SBezierLoopSet *loops,
Vector alongDir);
void MakeFromRevolution(SBezierLoopSet *loops,
Vector pt, Vector axis,
double angleSweep);
// 布尔合并
void MakeFromUnion(SShell *a, SShell *b);
void MakeFromDifference(SShell *a, SShell *b);
};
14.5.3 BSP树
// src/bsp.cpp
class SBsp3 {
public:
Vector n; // 分割平面法线
double d; // 分割平面距离
SBsp3 *pos; // 正侧子树
SBsp3 *neg; // 负侧子树
SMesh *Insert(SMesh *m);
void DebugDraw();
};
14.6 平台抽象层
14.6.1 Platform接口
// src/platform/platform.h
namespace Platform {
// 窗口管理
class Window {
public:
virtual void SetTitle(const std::string &title) = 0;
virtual void Invalidate() = 0;
virtual void GetClientSize(double *w, double *h) = 0;
};
// 文件对话框
class FileDialog {
public:
virtual bool Show() = 0;
virtual Path GetPath() = 0;
};
// 定时器
typedef std::function<void()> TimerCallback;
void ScheduleOnMainThread(TimerCallback cb, int ms);
// 剪贴板
void SetClipboardText(const std::string &text);
std::string GetClipboardText();
}
14.6.2 平台实现
platform/
├── guiwin.cpp # Windows GUI
├── guimac.mm # macOS GUI
├── guigtk.cpp # GTK GUI
├── guiqt.cpp # Qt GUI
└── guihtml.cpp # Web/Emscripten GUI
14.7 渲染系统
14.7.1 Canvas抽象
// src/render/render.h
class Canvas {
public:
virtual void DrawLine(Vector a, Vector b,
hStroke hcs) = 0;
virtual void DrawPolygon(const SPolygon &p,
hFill fill) = 0;
virtual void DrawMesh(const SMesh &m,
hFill fill, hStroke stroke) = 0;
// ...
};
14.7.2 OpenGL渲染器
// src/render/gl*.cpp
class OpenGLRenderer : public Canvas {
// OpenGL状态
GLuint vao, vbo;
Shader shader;
public:
void DrawLine(...) override;
void DrawPolygon(...) override;
void Flush();
};
14.8 文件格式
14.8.1 SLVS文件结构
SolveSpace Model File
Version: 4
Group.h.v=00000001
Group.type=5000
Group.name=sketch-in-plane
...
Entity.h.v=00010001
Entity.type=2000
Entity.workplane.v=80000001
...
Constraint.h.v=00020001
Constraint.type=20
...
Param.h.v=00030001
Param.val=50.000000
...
14.8.2 文件读写
// src/file.cpp
class FileReader {
char line[1024];
public:
bool ReadLine(const char **key, const char **val);
};
class FileWriter {
public:
void Write(const char *fmt, ...);
};
void SolveSpaceUI::SaveFile(const Platform::Path &path) {
FileWriter f(path);
f.Write("SolveSpace Model File\n");
f.Write("Version: %d\n", SLVS_VERSION);
for(auto &g : SK.group) {
g.SaveToFile(&f);
}
// ...
}
14.9 扩展点
14.9.1 添加新约束类型
// 1. 在 sketch.h 添加类型枚举
enum class Type : uint32_t {
// ... existing types
MY_NEW_CONSTRAINT = 999,
};
// 2. 实现方程生成
void ConstraintBase::GenerateEquations(IdList<Equation> *l) {
switch(type) {
case Type::MY_NEW_CONSTRAINT:
// 添加方程到 l
AddEq(l, /* expression */);
break;
}
}
// 3. 添加UI入口
void GraphicsWindow::MenuConstrain(Command id) {
case Command::CONSTRAIN_MY_NEW:
// 创建约束
break;
}
14.9.2 添加新实体类型
// 1. 添加类型枚举
// 2. 实现 EntityBase 的虚方法
// 3. 添加绘制代码
// 4. 添加序列化支持
14.9.3 添加新导出格式
// src/export.cpp
void SolveSpaceUI::ExportMyFormat(const Platform::Path &path) {
// 获取网格
SMesh *sm = &SK.GetGroup(SS.GW.activeGroup)->displayMesh;
// 写入文件
FILE *f = ssfopen(path, "wb");
// ... 格式特定代码
fclose(f);
}
14.10 总结
本章分析了SolveSpace的源码架构:
- 项目结构: 目录组织和模块划分
- 数据结构: 句柄系统、IdList、实体、约束、组
- 表达式系统: Expr类、符号微分
- 约束求解器: System类、求解流程
- 几何内核: 网格、曲面、BSP
- 平台层: 抽象接口和各平台实现
- 渲染系统: Canvas和OpenGL
- 文件格式: SLVS格式和读写
- 扩展点: 添加新功能的方法
下一章将介绍二次开发实战。
导航
- 上一章: 第13章 - Python绑定开发
- 下一章: 第15章 - 二次开发实战

浙公网安备 33010602011771号