源码架构分析

第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的源码架构:

  1. 项目结构: 目录组织和模块划分
  2. 数据结构: 句柄系统、IdList、实体、约束、组
  3. 表达式系统: Expr类、符号微分
  4. 约束求解器: System类、求解流程
  5. 几何内核: 网格、曲面、BSP
  6. 平台层: 抽象接口和各平台实现
  7. 渲染系统: Canvas和OpenGL
  8. 文件格式: SLVS格式和读写
  9. 扩展点: 添加新功能的方法

下一章将介绍二次开发实战。


导航


posted @ 2026-01-10 13:16  我才是银古  阅读(25)  评论(0)    收藏  举报