【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::mapO(log n) 查找
  • 缓存映射表避免重复构建
  • 小范围使用直接映射而非查找

12.2 内存使用优化

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

12.3 编译时优化

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

总结

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

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

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

相关推荐
Source.Liu2 小时前
【学写LibreCAD】单位转换系统 Rust 实现
qt·rust·cad
一只小bit2 小时前
Qt 信号与槽:信号产生与处理之间的重要函数
前端·c++·qt·cpp·页面
偶像你挑的噻2 小时前
1.Qt-编译器基本知识介绍
开发语言·qt
透明的玻璃杯2 小时前
VS2015 +QT5.9.9 环境问题注意事项
开发语言·qt
千千道2 小时前
QT上位机作为FTP客户端上传多文件
c++·qt
luoyayun3612 小时前
Qt/QML 实现类似Xmind简易思维导图绘制
qt·xmind·思维导图
九天轩辕2 小时前
基于 Qt 和 libimobiledevice 的跨平台 iOS 设备管理工具开发实践
开发语言·qt·ios
Source.Liu2 小时前
【学写LibreCAD】RS文件 Rust 实现
rust·cad
小尧嵌入式2 小时前
QT软件开发知识点流程及文本转语音工具
开发语言·c++·qt