模块概述
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)
按渲染顺序定义覆盖层元素:
OverlayEffects(0):特殊效果(如悬停发光)ActionPreviewEntity(1):动作预览实体Snapper(2):捕捉器(总是最后显示)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 添加新实体类型
- 在
EntityType枚举中添加新类型 - 注意注释中提到的顺序要求(特别是尺寸标注)
- 更新相关判断函数(如需要)
11.2 添加新线宽
- 在
LineWidth枚举中添加新值 - 更新映射表构建函数
- 更新DXF转换函数
11.3 添加新动作类型
- 在
ActionType枚举中添加新动作 - 确保动作工厂能处理新类型
- 更新相关的界面绑定
十二、性能考量
12.1 映射表查找优化
- 使用
std::map的O(log n)查找 - 缓存映射表避免重复构建
- 小范围使用直接映射而非查找
12.2 内存使用优化
- 枚举使用适当的基础类型(如
unsigned short) - 静态局部变量减少全局变量
- 内联小函数减少调用开销
12.3 编译时优化
- 大量使用
constexpr和内联函数 - 条件编译减少不必要的代码
- 头文件中的内联实现减少链接开销
总结
rs2 模块作为 LibreCAD 的基础,展现了优秀的设计理念:
- 类型安全:强类型枚举减少错误
- 性能优化:多种策略平衡速度与灵活性
- 可扩展性:清晰的扩展点和接口
- 兼容性:支持多种标准和格式
- 国际化:考虑全球用户需求
这个模块的设计体现了 CAD 软件对精确性、性能和可扩展性的严格要求,为 LibreCAD 的其余部分提供了坚实的基础框架。