【LibreCAD】RS2 模块完整解析

模块概述

rs2 模块是 LibreCAD 的核心基础模块,定义了整个项目的类型系统、枚举常量、转换函数和基本配置。它包含两个主要文件:

  • rs.h:头文件,定义所有类型和接口
  • rs.cpp:实现文件,提供转换函数的具体实现

一、文件结构

1.1 头文件 (rs.h) 结构

复制代码
rs.h
├── 预处理器指令和常量定义
├── 主命名空间 RS2
│   ├── 枚举类型定义 (Flags, EntityType, ActionType等)
│   ├── 类型转换函数声明
│   └── 内联辅助函数
├── 文本命名空间 Text
│   └── 文本相关枚举定义
└── 条件编译指令

1.2 实现文件 (rs.cpp) 结构

复制代码
rs.cpp
├── 包含的头文件
├── 匿名命名空间
│   ├── 内部映射表构建函数
│   └── 映射表获取函数
├── 公开转换函数实现
│   ├── intToLineWidth()
│   ├── lineWidthToInt()
│   ├── dxfInt2lineWidth()
│   └── lineWidth2dxfInt()
└── DXF兼容性处理

二、核心枚举类型系统

2.1 实体类型系统 (EntityType)

2.1.1 分类层次
复制代码
基本几何实体 (1-18)
├── EntityPoint
├── EntityLine
├── EntityArc
├── EntityCircle
├── EntityEllipse
├── EntityPolyline
└── ...

文本实体 (18-20)
├── EntityText
└── EntityMText

尺寸标注实体 (20-28)
├── EntityDimAligned
├── EntityDimLinear
├── EntityDimRadial
├── EntityDimDiametric
├── EntityDimAngular
├── EntityDimArc
├── EntityDimOrdinate
├── EntityTolerance
└── EntityDimLeader

高级实体 (28-...)
├── EntityHatch
├── EntityImage
├── EntitySpline
└── ...
2.1.2 实用函数
cpp 复制代码
// 判断是否为尺寸标注实体
inline bool isDimensionalEntity(EntityType type) {
    return (type >= EntityDimAligned) && (type <= EntityDimLeader);
}

// 判断是否为文本实体
inline bool isTextEntity(EntityType type) {
    return (type == EntityText) || (type == EntityMText);
}

2.2 标志位系统 (Flags)

2.2.1 标志位分类
复制代码
状态标志
├── FlagUndone     (1<<0): 可撤销状态
├── FlagSelected   (1<<8): 选中状态
├── FlagHighlighted(1<<14): 高亮显示

属性继承标志
├── FlagByLayer    (1<<2): 属性由图层定义
├── FlagByBlock    (1<<3): 属性由块定义

图层状态标志
├── FlagFrozen     (1<<4): 图层冻结
├── FlagLocked     (1<<6): 图层锁定

几何特性标志
├── FlagClosed     (1<<9): 多段线闭合
├── FlagHatchChild (1<<16): 剖面线子实体
2.2.2 使用示例
cpp 复制代码
// 设置多个标志
unsigned flags = RS2::FlagVisible | RS2::FlagByLayer | RS2::FlagSelected;

// 检查标志
if (flags & RS2::FlagSelected) {
    // 实体被选中
}

三、线宽转换系统(核心实现)

3.1 线宽枚举定义 (LineWidth)

定义了 24 种标准线宽,从 Width00 (0.00mm) 到 Width23 (2.11mm),以及特殊值:

  • WidthByLayer (-1): 继承图层线宽
  • WidthByBlock (-2): 继承块线宽
  • WidthDefault (-3): 使用默认线宽
  • WidthUnchanged (-4): 线宽未更改

3.2 转换系统架构

复制代码
三种表示形式之间的转换
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│                 │    │                 │    │                 │
│   LibreCAD      │◄──►│   内部整数     │◄──►│    DXF格式      │
│   枚举类型      │    │   表示形式      │    │    整数代码     │
│                 │    │                 │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘
        ▲                      ▲                       ▲
        │                      │                       │
        │    intToLineWidth()  │      dxfInt2lineWidth()│
        │    lineWidthToInt()  │      lineWidth2dxfInt()│
        │                      │                       │
        └───────────────────────────────────────────────┘

3.3 映射表设计

3.3.1 内部映射表结构
cpp 复制代码
// 整数到线宽枚举的映射
{
    {-4, WidthUnchanged},  // 特殊:未更改
    {-3, WidthDefault},    // 特殊:默认值
    {-2, WidthByBlock},    // 特殊:随块
    {-1, WidthByLayer},    // 特殊:随层
    {3, Width00},          // 0.00mm
    {8, Width01},          // 0.05mm
    {12, Width02},         // 0.09mm
    // ... 其他标准线宽
    {std::numeric_limits<int>::max(), Width23}  // 最大线宽
}
3.3.2 DXF转换的硬编码映射
cpp 复制代码
// 使用switch-case直接映射
switch (lw) {
    case WidthByLayer: return -1;
    case WidthByBlock: return -2;
    case WidthDefault: return -3;
    case Width00:      return 0;
    case Width01:      return 5;
    // ... 其他线宽
}

3.4 性能优化策略

3.4.1 静态局部变量缓存
cpp 复制代码
const std::map<int, RS2::LineWidth>& getInt2LineWidthMap() {
    // 首次调用时初始化,后续重用
    static std::map<int, RS2::LineWidth> g_int2LineWidth = constructInt2LineWidth();
    return g_int2LineWidth;
}
3.4.2 范围检查优化
cpp 复制代码
// DXF转换使用连续范围检查,避免映射表查找开销
RS2::LineWidth RS2::dxfInt2lineWidth(int i) {
    if (i < 0) {
        // 处理特殊值
    } else if (i < 3) {
        return Width00;
    } else if (i < 7) {
        return Width01;
    } // ... 其他范围
}

四、动作系统 (ActionType)

4.1 动作分类体系

复制代码
文件操作 (100-112)
├── ActionFileNew
├── ActionFileOpen
├── ActionFileExport
└── ActionFilePrint

编辑操作 (112-135)
├── ActionEditUndo
├── ActionEditCopy
├── ActionEditPaste
└── ActionOrderTop

视图操作 (135-160)
├── ActionZoomIn
├── ActionZoomOut
├── ActionZoomAuto
└── ActionSelect

绘图操作 (160-260+)
├── ActionDrawLine
├── ActionDrawCircle
├── ActionDrawArc
└── ActionDrawPolyline

标注操作 (260-280)
├── ActionDimLinear
├── ActionDimAngular
├── ActionDimRadial
└── ActionDimLeader

修改操作 (280-320)
├── ActionModifyMove
├── ActionModifyRotate
├── ActionModifyScale
└── ActionModifyTrim

图层块操作 (320-350)
├── ActionLayersAdd
├── ActionLayersEdit
├── ActionBlocksInsert
└── ActionBlocksExplode

4.2 交互式输入动作

cpp 复制代码
inline bool isInteractiveInputAction(ActionType type) {
    return type == ActionInteractivePickPoint ||
           type == ActionInteractivePickLength ||
           type == ActionInteractivePickAngle;
}

五、单位系统设计

5.1 完整的单位枚举 (Unit)

支持 21 种不同的测量单位:

复制代码
英制单位
├── Inch    : 英寸
├── Foot    : 12英寸
├── Mile    : 1760码
└── Yard    : 3英尺

公制单位
├── Millimeter  : 毫米
├── Centimeter  : 厘米
├── Meter       : 米
└── Kilometer   : 公里

科学单位
├── Angstrom    : 10^-10米
├── Nanometer   : 10^-9米
├── Micron      : 10^-6米
└── Lightyear   : 光年

5.2 线性格式支持

  • Scientific:科学计数法
  • Decimal:十进制小数
  • Engineering:工程格式(如 7' 11.5")
  • Architectural:建筑格式(如 7'-9 1/8")
  • Fractional:分数格式

六、国际化与本地化支持

6.1 文本方向处理

cpp 复制代码
namespace Text {
    enum TextLocaleDirection {
        locLeftToRight,     // 从左到右(如英语、中文)
        locRightToLeft      // 从右到左(如阿拉伯语、希伯来语)
    };
    
    enum MTextDrawingDirection {
        LeftToRight,       // 多行文本从左到右
        RightToLeft,       // 多行文本从右到左
        TopToBottom,       // 从上到下(如中文传统排版)
        ByStyle           // 继承文本样式
    };
}

6.2 文字生成方向

cpp 复制代码
enum TextGeneration {
    None,        // 正常文本
    Backward,    // X轴镜像(水平翻转)
    UpsideDown   // Y轴镜像(垂直翻转)
};

七、渲染系统配置

7.1 绘图模式 (DrawingMode)

  • ModeFull:完整渲染(默认)
  • ModePreview:预览模式(黑白无样式)
  • ModeBW:黑白模式(适合打印)
  • ModeWB:白黑模式(适合深色背景导出)

7.2 重绘方法优化 (RedrawMethod)

使用位标志组合,优化渲染性能:

cpp 复制代码
enum RedrawMethod {
    RedrawNone = 0,
    RedrawGrid = 1,      // 只重绘网格
    RedrawOverlay = 2,   // 只重绘覆盖层
    RedrawDrawing = 4,   // 只重绘绘图内容
    RedrawAll = 0xffff   // 重绘所有
};

// 使用示例
int method = RS2::RedrawGrid | RS2::RedrawOverlay;
// 只更新网格和覆盖层,不重绘整个图形

7.3 覆盖层图形顺序 (OverlayGraphics)

按渲染顺序定义覆盖层元素:

  1. OverlayEffects (0):特殊效果(如悬停发光)
  2. ActionPreviewEntity (1):动作预览实体
  3. Snapper (2):捕捉器(总是最后显示)
  4. InfoCursor (3):信息光标

八、几何计算常量

8.1 容差系统

cpp 复制代码
#define RS_TOLERANCE      1.0e-10     // 基本几何容差
#define RS_TOLERANCE15    1.5e-15     // 平方容差
#define RS_TOLERANCE2     1.0e-20     // 高精度容差
#define RS_TOLERANCE_ANGLE 1.0e-8     // 角度容差

8.2 平台兼容性处理

由于 Windows XP 对 MAXDOUBLE/MINDOUBLE 的处理问题,定义了替代值:

cpp 复制代码
#define RS_MAXDOUBLE 1.0E+10
#define RS_MINDOUBLE -1.0E+10

九、代码设计模式应用

9.1 工厂模式 (Factory Pattern)

通过映射表工厂函数创建转换关系:

cpp 复制代码
std::map<int, RS2::LineWidth> constructInt2LineWidth() {
    return { /* 初始化映射表 */ };
}

9.2 单例模式 (Singleton Pattern)

确保映射表全局唯一:

cpp 复制代码
const std::map<int, RS2::LineWidth>& getInt2LineWidthMap() {
    static std::map<int, RS2::LineWidth> g_int2LineWidth = constructInt2LineWidth();
    return g_int2LineWidth;
}

9.3 策略模式 (Strategy Pattern)

不同的转换使用不同策略:

  • 内部转换:使用映射表策略
  • DXF转换:使用范围检查策略

9.4 建造者模式 (Builder Pattern)

通过辅助函数构建反向映射:

cpp 复制代码
std::map<RS2::LineWidth, int> constructReversedMap(
    const std::map<int, RS2::LineWidth>& originalMap) {
    // 构建反向映射
}

十、实际应用示例

10.1 DXF文件导入

cpp 复制代码
// 导入DXF文件时的线宽处理
int dxfLineWidth = readFromDXF();  // 从DXF读取线宽值
RS2::LineWidth lw = RS2::dxfInt2lineWidth(dxfLineWidth);
entity->setPenWidth(lw);

10.2 内部操作

cpp 复制代码
// 用户界面调整线宽
int uiValue = getFromUI();  // 从UI获取值
RS2::LineWidth lw = RS2::intToLineWidth(uiValue);
entity->setPenWidth(lw);

// 保存到设置
int saveValue = RS2::lineWidthToInt(lw);
saveToSettings(saveValue);

10.3 实体类型判断

cpp 复制代码
// 处理不同的实体类型
switch (entity->rtti()) {
    case RS2::EntityLine:
        // 处理直线
        break;
    case RS2::EntityDimLinear:
        // 处理线性标注
        break;
    case RS2::EntityHatch:
        // 处理剖面线
        break;
}

十一、模块扩展指南

11.1 添加新实体类型

  1. 在 EntityType 枚举中添加新类型
  2. 注意注释中提到的顺序要求(特别是尺寸标注)
  3. 更新相关判断函数(如需要)

11.2 添加新线宽

  1. 在 LineWidth 枚举中添加新值
  2. 更新映射表构建函数
  3. 更新DXF转换函数

11.3 添加新动作类型

  1. 在 ActionType 枚举中添加新动作
  2. 确保动作工厂能处理新类型
  3. 更新相关的界面绑定

十二、性能考量

12.1 映射表查找优化

  • 使用 std::map 的 O(log n) 查找
  • 缓存映射表避免重复构建
  • 小范围使用直接映射而非查找

12.2 内存使用优化

  • 枚举使用适当的基础类型(如 unsigned short)
  • 静态局部变量减少全局变量
  • 内联小函数减少调用开销

12.3 编译时优化

  • 大量使用 constexpr 和内联函数
  • 条件编译减少不必要的代码
  • 头文件中的内联实现减少链接开销

总结

rs2 模块作为 LibreCAD 的基础,展现了优秀的设计理念:

  1. 类型安全:强类型枚举减少错误
  2. 性能优化:多种策略平衡速度与灵活性
  3. 可扩展性:清晰的扩展点和接口
  4. 兼容性:支持多种标准和格式
  5. 国际化:考虑全球用户需求

这个模块的设计体现了 CAD 软件对精确性、性能和可扩展性的严格要求,为 LibreCAD 的其余部分提供了坚实的基础框架。

相关推荐
扶尔魔ocy2 小时前
【qt openGL入门笔记】OSG实现飞机模型在网格图上飞行
qt·opengl·osg
西飘客11 小时前
vs 怎么根据dll 生成lib文件
c++·qt
bkspiderx12 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
半杯咖啡半行码15 小时前
Qt开发实战:数据库、MV 模式、QProcess与串口通信全攻略
数据库·qt
时间的拾荒人16 小时前
Qt 界面优化:绘图详解 —— 从基础图形到图片处理
开发语言·qt·面试
我才是银古16 小时前
大坐标、镜像与弦高:.NET CSG 库的工程笔记
3d·cad·csg
MayZork16 小时前
Qt 文件操作:QSaveFile 与 QTemporaryFile(含 QTemporaryDir)实战
开发语言·qt
半杯咖啡半行码20 小时前
Qt 开发基础:版本演进、常用工具与多平台安装
开发语言·qt
qq_401700411 天前
Qt Signal Mapper:一堆按钮,怎么共用一个槽函数
开发语言·qt