第03章-核心架构解析

第三章:核心架构解析

3.1 架构概述

QCAD采用分层的模块化架构设计,将核心功能、用户界面和扩展系统清晰分离。这种设计使得QCAD既保持了高性能的核心运算能力,又提供了强大的可扩展性。

3.1.1 整体架构图

┌─────────────────────────────────────────────────────────────┐
│                    用户界面层 (UI Layer)                      │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐           │
│  │ 菜单栏   │ │ 工具栏  │ │ 绘图区  │ │ 面板    │           │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘           │
├─────────────────────────────────────────────────────────────┤
│                   脚本层 (Script Layer)                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ECMAScript/JavaScript 引擎 (Qt Script)               │   │
│  │ • 工具脚本 • UI组件 • 自动化脚本 • 插件脚本         │   │
│  └─────────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────────┤
│                   核心层 (Core Layer)                        │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐       │
│  │ RDocument │ │ REntity  │ │ RStorage │ │ RExporter│       │
│  │ 文档管理  │ │ 实体系统 │ │ 存储接口 │ │ 导出系统 │       │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘       │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐       │
│  │ RMath    │ │ RVector  │ │ RBox     │ │ RArc     │       │
│  │ 数学库   │ │ 向量类   │ │ 包围盒   │ │ 几何类   │       │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘       │
├─────────────────────────────────────────────────────────────┤
│                    平台层 (Platform Layer)                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              Qt Framework 5.x / 6.x                  │   │
│  │   • QtCore • QtGui • QtWidgets • QtScript           │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

3.1.2 设计原则

QCAD的架构遵循以下设计原则:

  1. 模块化设计

    • 功能分离为独立模块
    • 模块间通过明确的接口通信
    • 便于维护和扩展
  2. 分层架构

    • 核心层提供基础功能
    • 脚本层实现业务逻辑
    • UI层处理用户交互
  3. 开放扩展

    • 几乎所有API对脚本开放
    • 支持C++和JavaScript两种扩展方式
    • 插件系统设计完善
  4. 跨平台兼容

    • 基于Qt框架
    • 抽象平台差异
    • 统一的代码库

3.2 源码目录结构

3.2.1 主要目录

qcad/
├── src/                    # C++源代码
│   ├── core/               # 核心模块
│   ├── entity/             # 实体定义
│   ├── gui/                # 图形界面
│   ├── grid/               # 网格系统
│   ├── snap/               # 捕捉系统
│   ├── operations/         # 操作命令
│   ├── spatialindex/       # 空间索引
│   └── stemmer/            # 文本处理
├── scripts/                # JavaScript脚本
│   ├── Draw/               # 绘图工具
│   ├── Edit/               # 编辑工具
│   ├── File/               # 文件操作
│   ├── Modify/             # 修改工具
│   ├── View/               # 视图控制
│   ├── Snap/               # 捕捉设置
│   ├── Layer/              # 图层管理
│   ├── Block/              # 块管理
│   ├── Dimension/          # 标注工具
│   ├── Misc/               # 其他工具
│   └── Pro/                # 专业版功能
├── plugins/                # 插件目录
├── fonts/                  # 字体文件
├── libraries/              # 符号库
├── patterns/               # 填充图案
├── linetypes/              # 线型定义
├── themes/                 # 主题文件
├── ts/                     # 翻译文件
└── examples/               # 示例文件

3.2.2 核心源码模块

src/core/ - 核心模块

core/
├── RDocument.cpp           # 文档类
├── RDocumentInterface.cpp  # 文档接口
├── REntity.cpp             # 实体基类
├── RStorage.cpp            # 存储抽象
├── RMemoryStorage.cpp      # 内存存储
├── RSpatialIndex.cpp       # 空间索引
├── RTransaction.cpp        # 事务处理
├── RUcs.cpp                # 用户坐标系
├── RLayer.cpp              # 图层
├── RLinetype.cpp           # 线型
├── RBlock.cpp              # 块定义
├── RView.cpp               # 视图
└── ...

src/entity/ - 实体模块

entity/
├── RLineEntity.cpp         # 直线
├── RArcEntity.cpp          # 圆弧
├── RCircleEntity.cpp       # 圆
├── REllipseEntity.cpp      # 椭圆
├── RPolylineEntity.cpp     # 多段线
├── RSplineEntity.cpp       # 样条曲线
├── RTextEntity.cpp         # 文本
├── RDimensionEntity.cpp    # 标注
├── RHatchEntity.cpp        # 图案填充
├── RImageEntity.cpp        # 图像
├── RBlockReferenceEntity.cpp # 块参照
└── ...

3.2.3 脚本目录结构

scripts/Draw/ - 绘图工具

Draw/
├── Line/                   # 直线工具
│   ├── Line.js
│   ├── Line2P.js           # 两点直线
│   ├── LineAngle.js        # 角度直线
│   ├── LineHorizontal.js   # 水平线
│   └── ...
├── Arc/                    # 圆弧工具
├── Circle/                 # 圆工具
├── Ellipse/                # 椭圆工具
├── Polyline/               # 多段线工具
├── Spline/                 # 样条工具
├── Shape/                  # 形状工具
├── Text/                   # 文本工具
└── Hatch/                  # 填充工具

3.3 文档模型

3.3.1 RDocument类

RDocument是QCAD的核心类,代表一个CAD文档(图纸)。它管理文档中的所有实体、图层、块等元素。

主要职责

  • 管理所有实体对象
  • 维护图层、块、线型等定义
  • 提供空间索引用于快速查询
  • 处理事务和撤销/重做
  • 存储文档属性和变量

类定义概览

class RDocument : public RRequireHeap {
public:
    // 构造和初始化
    RDocument(RStorage& storage, RSpatialIndex& spatialIndex);
    
    // 实体管理
    void addEntity(REntity* entity);
    void removeEntity(REntity::Id entityId);
    QSet<REntity::Id> queryAllEntities() const;
    REntity* queryEntity(REntity::Id entityId) const;
    
    // 图层管理
    void addLayer(RLayer* layer);
    RLayer* queryLayer(RLayer::Id layerId) const;
    RLayer* queryLayer(const QString& layerName) const;
    
    // 块管理
    void addBlock(RBlock* block);
    RBlock* queryBlock(RBlock::Id blockId) const;
    
    // 空间查询
    QSet<REntity::Id> queryIntersectedEntities(const RBox& box) const;
    QSet<REntity::Id> queryContainedEntities(const RBox& box) const;
    
    // 文档属性
    RBox getBoundingBox() const;
    void setVariable(const QString& key, const QVariant& value);
    QVariant getVariable(const QString& key) const;
    
    // 事务
    RTransaction startTransaction();
    void endTransaction();
    void undo();
    void redo();
    
private:
    RStorage* storage;           // 存储后端
    RSpatialIndex* spatialIndex; // 空间索引
    RTransactionStack* transactionStack;
};

3.3.2 RDocumentInterface类

RDocumentInterface提供了文档与用户界面之间的高级接口,协调文档操作、视图更新和用户交互。

主要职责

  • 连接文档和视图
  • 处理用户操作
  • 管理选择集
  • 协调命令执行

类定义概览

class RDocumentInterface {
public:
    RDocumentInterface(RDocument& document);
    
    // 文档访问
    RDocument& getDocument();
    RStorage& getStorage();
    
    // 视图管理
    void addView(RGraphicsView* view);
    void removeView(RGraphicsView* view);
    void regenerateViews();
    void regenerateScenes();
    
    // 选择管理
    void selectEntity(REntity::Id entityId);
    void deselectEntity(REntity::Id entityId);
    void selectAll();
    void deselectAll();
    QSet<REntity::Id> getSelectedEntities() const;
    
    // 操作执行
    void applyOperation(ROperation* operation);
    
    // 坐标转换
    RVector snap(const RVector& position);
    
    // 属性
    void setCurrentLayer(const QString& layerName);
    void setCurrentColor(const RColor& color);
    
private:
    RDocument& document;
    QList<RGraphicsView*> views;
    QSet<REntity::Id> selectedEntities;
};

3.3.3 存储系统

QCAD使用抽象的存储系统,支持不同的存储后端:

RStorage - 存储抽象基类

class RStorage {
public:
    virtual ~RStorage() {}
    
    // 实体存储
    virtual void saveEntity(REntity* entity) = 0;
    virtual REntity* loadEntity(REntity::Id id) = 0;
    virtual void deleteEntity(REntity::Id id) = 0;
    
    // 图层存储
    virtual void saveLayer(RLayer* layer) = 0;
    virtual RLayer* loadLayer(RLayer::Id id) = 0;
    
    // 查询
    virtual QSet<REntity::Id> queryAllEntities() = 0;
    virtual QSet<REntity::Id> queryLayerEntities(RLayer::Id layerId) = 0;
};

RMemoryStorage - 内存存储实现

  • 将所有数据存储在内存中
  • 适用于小型文档
  • 快速访问

RLinkedStorage - 链接存储实现

  • 支持文档链接
  • 适用于外部参照

3.4 实体系统

3.4.1 实体类层次

QCAD中所有可绘制对象都继承自REntity基类:

RObject
└── REntity (实体基类)
    ├── RLineEntity (直线)
    ├── RArcEntity (圆弧)
    ├── RCircleEntity (圆)
    ├── REllipseEntity (椭圆)
    ├── RPolylineEntity (多段线)
    ├── RSplineEntity (样条曲线)
    ├── RPointEntity (点)
    ├── RTextEntity (文本)
    │   └── RTextBasedEntity
    │       ├── RAttributeEntity (属性)
    │       └── RAttributeDefinitionEntity (属性定义)
    ├── RDimensionEntity (标注)
    │   ├── RDimLinearEntity (线性标注)
    │   ├── RDimAlignedEntity (对齐标注)
    │   ├── RDimAngularEntity (角度标注)
    │   ├── RDimRadialEntity (半径标注)
    │   ├── RDimDiametricEntity (直径标注)
    │   └── RDimOrdinateEntity (坐标标注)
    ├── RHatchEntity (填充)
    ├── RImageEntity (图像)
    ├── RBlockReferenceEntity (块参照)
    ├── RLeaderEntity (引线)
    ├── RSolidEntity (实体填充)
    ├── RTraceEntity (轨迹)
    └── RViewportEntity (视口)

3.4.2 REntity基类

REntity是所有实体的基类,定义了实体的通用接口:

class REntity : public RObject {
public:
    typedef int Id;
    
    // 图层和块
    RLayer::Id getLayerId() const;
    void setLayerId(RLayer::Id layerId);
    RBlock::Id getBlockId() const;
    void setBlockId(RBlock::Id blockId);
    
    // 几何属性
    virtual RBox getBoundingBox() const = 0;
    virtual double getLength() const;
    virtual double getArea() const;
    virtual RVector getClosestPointOnEntity(const RVector& point) const;
    virtual double getDistanceTo(const RVector& point) const;
    
    // 变换
    virtual void move(const RVector& offset);
    virtual void rotate(double angle, const RVector& center);
    virtual void scale(double factor, const RVector& center);
    virtual void mirror(const RLine& axis);
    
    // 绘制
    virtual void exportEntity(RExporter& exporter) const = 0;
    
    // 属性
    void setColor(const RColor& color);
    RColor getColor() const;
    void setLinetype(const RLinetype& linetype);
    void setLineweight(double lineweight);
    
    // 选择
    bool isSelected() const;
    void setSelected(bool on);
    
protected:
    RLayer::Id layerId;
    RBlock::Id blockId;
    RColor color;
    RLinetype linetype;
    double lineweight;
    bool selected;
};

3.4.3 实体数据类

每个实体都有对应的数据类,存储实体的几何信息:

RLineData - 直线数据

class RLineData : public REntityData {
public:
    RLineData();
    RLineData(const RVector& startPoint, const RVector& endPoint);
    
    RVector getStartPoint() const { return startPoint; }
    RVector getEndPoint() const { return endPoint; }
    void setStartPoint(const RVector& p) { startPoint = p; }
    void setEndPoint(const RVector& p) { endPoint = p; }
    
    double getLength() const;
    double getAngle() const;
    RVector getMiddlePoint() const;
    
private:
    RVector startPoint;
    RVector endPoint;
};

RArcData - 圆弧数据

class RArcData : public REntityData {
public:
    RArcData();
    RArcData(const RVector& center, double radius, 
             double startAngle, double endAngle, bool reversed);
    
    RVector getCenter() const { return center; }
    double getRadius() const { return radius; }
    double getStartAngle() const { return startAngle; }
    double getEndAngle() const { return endAngle; }
    bool isReversed() const { return reversed; }
    
    double getLength() const;
    RVector getStartPoint() const;
    RVector getEndPoint() const;
    RVector getMiddlePoint() const;
    
private:
    RVector center;
    double radius;
    double startAngle;
    double endAngle;
    bool reversed;
};

3.4.4 实体工厂

QCAD使用工厂模式创建实体:

class REntityFactory {
public:
    static REntity* create(const QString& entityType);
    static void registerEntity(const QString& type, 
                               REntity* (*creator)());
    
private:
    static QMap<QString, REntity* (*)(void)> creators;
};

// 注册实体类型
REntityFactory::registerEntity("RLineEntity", 
    []() -> REntity* { return new RLineEntity(); });

3.5 图形视图系统

3.5.1 RGraphicsView类

RGraphicsView负责文档的可视化呈现:

class RGraphicsView : public QWidget {
public:
    RGraphicsView(RDocument* document);
    
    // 视图控制
    void zoomIn();
    void zoomOut();
    void zoomToFit();
    void zoomToRect(const RBox& rect);
    void pan(const RVector& offset);
    
    // 坐标转换
    RVector mapToModel(const QPoint& screenPoint) const;
    QPoint mapToScreen(const RVector& modelPoint) const;
    
    // 视图属性
    void setFactor(double factor);
    double getFactor() const;
    void setOffset(const RVector& offset);
    RVector getOffset() const;
    
    // 网格
    void setGridVisible(bool visible);
    bool isGridVisible() const;
    
    // 渲染
    void repaintView();
    void regenerate();
    
protected:
    void paintEvent(QPaintEvent* event) override;
    void wheelEvent(QWheelEvent* event) override;
    void mousePressEvent(QMouseEvent* event) override;
    void mouseMoveEvent(QMouseEvent* event) override;
    void mouseReleaseEvent(QMouseEvent* event) override;
    
private:
    RDocument* document;
    RGraphicsScene* scene;
    double factor;      // 缩放因子
    RVector offset;     // 平移偏移
    bool gridVisible;
};

3.5.2 RGraphicsScene类

RGraphicsScene管理图形场景中的所有图形项:

class RGraphicsScene : public QGraphicsScene {
public:
    RGraphicsScene(RDocument* document);
    
    // 重新生成
    void regenerate();
    void regenerateEntity(REntity::Id entityId);
    
    // 实体项管理
    void addEntityItem(REntity::Id entityId, QGraphicsItem* item);
    void removeEntityItem(REntity::Id entityId);
    QGraphicsItem* getEntityItem(REntity::Id entityId) const;
    
    // 高亮
    void highlightEntity(REntity::Id entityId);
    void dehighlightEntity(REntity::Id entityId);
    
private:
    RDocument* document;
    QMap<REntity::Id, QGraphicsItem*> entityItems;
};

3.5.3 导出器系统

RExporter用于将实体转换为图形输出:

class RExporter {
public:
    virtual ~RExporter() {}
    
    // 开始/结束
    virtual void startExport() {}
    virtual void endExport() {}
    
    // 图形元素输出
    virtual void exportLine(const RLine& line) = 0;
    virtual void exportArc(const RArc& arc) = 0;
    virtual void exportCircle(const RCircle& circle) = 0;
    virtual void exportEllipse(const REllipse& ellipse) = 0;
    virtual void exportPolyline(const RPolyline& polyline) = 0;
    virtual void exportSpline(const RSpline& spline) = 0;
    virtual void exportText(const RTextData& text) = 0;
    
    // 属性
    virtual void setColor(const RColor& color) {}
    virtual void setLinetype(const RLinetype& linetype) {}
    virtual void setLineweight(double lineweight) {}
};

// 图形场景导出器
class RGraphicsSceneExporter : public RExporter {
public:
    RGraphicsSceneExporter(QGraphicsScene* scene);
    
    void exportLine(const RLine& line) override;
    void exportArc(const RArc& arc) override;
    // ...
    
private:
    QGraphicsScene* scene;
};

// PDF导出器
class RPdfExporter : public RExporter {
public:
    RPdfExporter(const QString& fileName);
    // ...
};

// SVG导出器
class RSvgExporter : public RExporter {
public:
    RSvgExporter(const QString& fileName);
    // ...
};

3.6 事务与撤销系统

3.6.1 RTransaction类

RTransaction管理文档修改的原子操作:

class RTransaction {
public:
    RTransaction(RDocument& document);
    
    // 操作记录
    void addEntity(REntity* entity);
    void modifyEntity(REntity* entity);
    void deleteEntity(REntity::Id entityId);
    
    // 事务控制
    void commit();
    void rollback();
    
    // 撤销/重做
    void undo();
    void redo();
    
    // 状态
    bool isEmpty() const;
    bool isValid() const;
    
private:
    RDocument& document;
    QList<ROperation*> operations;
    bool committed;
};

3.6.2 撤销/重做实现

class RTransactionStack {
public:
    void push(RTransaction* transaction);
    RTransaction* pop();
    
    void undo();
    void redo();
    
    bool canUndo() const;
    bool canRedo() const;
    
    void clear();
    
private:
    QStack<RTransaction*> undoStack;
    QStack<RTransaction*> redoStack;
};

3.7 空间索引系统

3.7.1 RSpatialIndex类

RSpatialIndex提供高效的空间查询能力:

class RSpatialIndex {
public:
    virtual ~RSpatialIndex() {}
    
    // 添加/删除
    virtual void addEntity(REntity* entity) = 0;
    virtual void removeEntity(REntity::Id entityId) = 0;
    virtual void updateEntity(REntity* entity) = 0;
    
    // 空间查询
    virtual QSet<REntity::Id> queryIntersected(const RBox& box) const = 0;
    virtual QSet<REntity::Id> queryContained(const RBox& box) const = 0;
    virtual QSet<REntity::Id> queryNearby(const RVector& point, 
                                          double radius) const = 0;
    
    // 最近实体
    virtual REntity::Id queryNearest(const RVector& point) const = 0;
    
    virtual void clear() = 0;
};

// 基于R-Tree的实现
class RSpatialIndexRTree : public RSpatialIndex {
    // 使用Boost.Geometry R-Tree实现
};

// 简单的网格实现
class RSpatialIndexGrid : public RSpatialIndex {
    // 使用规则网格划分
};

3.7.2 空间查询示例

// 查询矩形区域内的实体
RBox selectionBox(RVector(0, 0), RVector(100, 100));
QSet<REntity::Id> entities = document.queryContainedEntities(selectionBox);

// 查询与给定点最近的实体
RVector clickPoint(50, 50);
REntity::Id nearestId = spatialIndex.queryNearest(clickPoint);
REntity* entity = document.queryEntity(nearestId);

// 查询与给定包围盒相交的实体
QSet<REntity::Id> intersected = document.queryIntersectedEntities(selectionBox);

3.8 模块系统

3.8.1 模块组织

QCAD的源码组织为多个模块:

模块 说明
core 核心类、文档模型、基础设施
entity 实体类定义
gui 图形用户界面
grid 网格系统
snap 捕捉系统
operations 操作和命令
spatialindex 空间索引
io 文件输入输出
dxf DXF格式处理

3.8.2 模块依赖关系

                    ┌─────┐
                    │ gui │
                    └──┬──┘
                       │
         ┌─────────────┼─────────────┐
         │             │             │
    ┌────▼───┐   ┌────▼────┐  ┌────▼────┐
    │  snap  │   │operations│  │  grid   │
    └────┬───┘   └────┬─────┘  └────┬────┘
         │            │              │
         └────────────┼──────────────┘
                      │
                ┌─────▼─────┐
                │   entity  │
                └─────┬─────┘
                      │
                ┌─────▼─────┐
                │   core    │
                └───────────┘

3.9 本章小结

本章深入分析了QCAD的核心架构:

  1. 整体架构

    • 分层设计(平台层、核心层、脚本层、UI层)
    • 模块化组织
    • 清晰的职责分离
  2. 文档模型

    • RDocument管理文档内容
    • RDocumentInterface协调文档与界面
    • 抽象存储系统
  3. 实体系统

    • 继承层次清晰
    • 实体与数据分离
    • 工厂模式创建
  4. 图形视图

    • RGraphicsView处理视图
    • RGraphicsScene管理场景
    • 导出器模式输出
  5. 事务系统

    • 事务保证原子操作
    • 完整的撤销/重做支持
  6. 空间索引

    • 高效的空间查询
    • 多种索引实现

理解这些核心概念对于深入使用QCAD和进行二次开发至关重要。


下一章预告:第四章将详细介绍QCAD的用户界面,包括各个界面组件的功能和使用方法。

posted @ 2026-01-11 00:40  我才是银古  阅读(4)  评论(0)    收藏  举报