第三章:核心架构与分层设计
3.1 架构设计理念
3.1.1 分层架构原则
LightCAD采用严格的分层架构(Layered Architecture),这是企业级软件开发中最经典也最可靠的架构模式之一。其核心原则包括:
- 单向依赖:上层模块可以依赖下层模块,但下层模块不能依赖上层模块
- 职责分离:每一层只负责特定的功能域
- 接口隔离:层与层之间通过明确定义的接口通信
- 可替换性:每一层的实现可以独立替换,只要接口保持不变
3.1.2 设计模式应用
LightCAD在架构设计中大量使用了经典设计模式:
| 设计模式 | 应用场景 | 具体实现 |
|---|---|---|
| 分层模式 | 整体架构 | Math→Core→RenderUtils→Drawing→Runtime |
| 命令模式 | 操作系统 | ActionCmds、ElementAction |
| 策略模式 | 渲染引擎 | Three.js/OpenTK不同渲染器 |
| 工厂模式 | 组件创建 | ComponentCreator |
| 观察者模式 | 变更通知 | IUpdateObject |
| 组合模式 | 层次实体 | LcGroup3、LcArray3 |
| 插件模式 | 扩展系统 | Weikio PluginFramework |
| MVVM模式 | UI绑定 | Avalonia XAML |
3.2 分层架构详解
3.2.1 层次总览
LightCAD的分层架构从底层到顶层分为六个主要层次:
┌─────────────────────────────────────────────────────┐
│ 第6层 用户界面层(Presentation Layer) │
│ LightCAD.WinForm + LightCAD.Model │
├─────────────────────────────────────────────────────┤
│ 第5层 应用运行时层(Application Runtime Layer) │
│ LightCAD.Runtime │
├─────────────────────────────────────────────────────┤
│ 第4层 绘图交互层(Drawing Interaction Layer) │
│ LightCAD.Drawing │
├─────────────────────────────────────────────────────┤
│ 第3层 渲染工具层(Render Utilities Layer) │
│ LightCAD.RenderUtils │
├─────────────────────────────────────────────────────┤
│ 第2层 核心数据层(Core Data Layer) │
│ LightCAD.Core │
├─────────────────────────────────────────────────────┤
│ 第1层 数学基础层(Math Foundation Layer) │
│ LightCAD.MathLib │
└─────────────────────────────────────────────────────┘
3.2.2 第1层:数学基础层(LightCAD.MathLib)
职责:提供所有数学运算的基础支持
模块结构:
LightCAD.MathLib/
├── Basic/ # 基本数学类型
│ ├── Point2d.cs # 二维点
│ ├── Point3d.cs # 三维点
│ ├── Vector2d.cs # 二维向量
│ ├── Vector3d.cs # 三维向量
│ ├── Matrix3d.cs # 3×3矩阵
│ ├── Matrix4d.cs # 4×4变换矩阵
│ └── BoundingBox.cs # 包围盒
├── Curve/ # 曲线数学
│ ├── BezierCurve.cs # 贝塞尔曲线
│ ├── NurbsCurve.cs # NURBS曲线
│ └── ArcMath.cs # 圆弧数学
├── Intersection/ # 交集计算
│ ├── LineIntersect.cs # 直线求交
│ ├── CurveIntersect.cs # 曲线求交
│ └── SurfaceIntersect.cs # 曲面求交
└── Utilities/ # 工具函数
├── Tolerance.cs # 精度容差
├── AngleUtils.cs # 角度工具
└── GeometryUtils.cs # 几何工具
关键特点:
- 无外部依赖(除MathNet.Numerics外)
- 所有计算使用双精度浮点数
- 内置容差比较机制
- 性能优化的矩阵运算
示例代码:
// 基本的向量和矩阵运算
var point = new Point3d(1.0, 2.0, 3.0);
var vector = new Vector3d(0.0, 0.0, 1.0);
// 创建变换矩阵(绕Z轴旋转45度)
var rotation = Matrix4d.CreateRotationZ(Math.PI / 4);
// 应用变换
var transformed = rotation.Transform(point);
// 计算两条直线的交点
var p1 = new Point2d(0, 0);
var d1 = new Vector2d(1, 1);
var p2 = new Point2d(1, 0);
var d2 = new Vector2d(0, 1);
var intersection = LineIntersect.Compute(p1, d1, p2, d2);
3.2.3 第2层:核心数据层(LightCAD.Core)
职责:定义CAD系统的核心数据模型
模块结构:
LightCAD.Core/
├── Elements/ # 图元实体
│ ├── Basic/ # 2D基本图元
│ ├── Element3d/ # 3D图元
│ ├── Solid/ # 实体建模
│ ├── Dim/ # 2D标注
│ ├── Dim3/ # 3D标注
│ ├── Table/ # 表格
│ ├── Mass/ # 质量属性
│ ├── Misc/ # 杂项
│ ├── Ref/ # 引用
│ └── VoidElement/ # 空元素
├── LcDocument.cs # 文档容器
├── LcEntity.cs # 实体基类
├── LcText.cs # 文本元素
├── ElementType.cs # 元素类型定义
└── IUpdateObject.cs # 更新接口
核心类层次:
LcEntity (实体基类)
├── LcLine # 直线
├── LcArc # 圆弧
├── LcCircle # 圆
├── LcEllipse # 椭圆
├── LcPolyline # 多段线
├── LcPolygon # 多边形
├── LcSpline # 样条曲线
├── LcText # 文本
├── LcLine3d # 3D直线
├── LcArc3d # 3D圆弧
├── LcCircle3d # 3D圆
├── LcSolid3d # 3D实体
├── LcExtrude3d # 拉伸体
├── LcRevolve3d # 旋转体
├── LcLoft3d # 放样体
├── LcBlend3d # 融合体
├── LcMesh3d # 网格体
└── ...
关键特点:
- 依赖MathLib层和ThreeJs4Net(字体管理)
- 实体采用组合模式组织层次关系
- 实现IUpdateObject接口支持变更通知
- ElementType系统支持自定义元素类型注册
3.2.4 第3层:渲染工具层(LightCAD.RenderUtils)
职责:在Core和Runtime之间架起渲染桥梁
模块结构:
LightCAD.RenderUtils/
├── 3dcontrols/ # 3D操控器
│ ├── Gizmo.cs # 变换手柄
│ ├── Manipulator.cs # 操控器
│ └── Handle3d.cs # 3D句柄
├── AssetManagers/ # 资源管理
│ ├── MaterialManager.cs # 材质管理
│ ├── TextureManager.cs # 纹理管理
│ └── FontManager.cs # 字体管理
├── ThreeUtils/ # Three.js工具
│ ├── SceneHelper.cs # 场景辅助
│ ├── CameraHelper.cs # 相机辅助
│ └── LightHelper.cs # 光照辅助
└── Events/ # 事件系统
├── RenderEvent.cs # 渲染事件
└── SelectionEvent.cs # 选择事件
关键特点:
- 核心桥接层,连接数据和显示
- 支持无编辑环境的纯渲染场景
- 管理3D操控器和交互句柄
- 提供统一的资源管理接口
架构备忘(摘自框架结构备忘.txt):
编辑环境: Core → RenderUtils → Runtime
无头环境: Core → Base → RenderUtils → 客户端程序
这意味着RenderUtils被设计为可以在没有完整编辑环境的情况下工作,支持服务端渲染或批处理场景。
3.2.5 第4层:绘图交互层(LightCAD.Drawing)
职责:管理二维绘图视口和用户交互
模块结构:
LightCAD.Drawing/
├── InputSys/ # 输入系统
│ ├── Inputer.cs # 输入处理器
│ ├── MouseHandler.cs # 鼠标处理
│ └── KeyHandler.cs # 键盘处理
├── Snap/ # 捕捉系统
│ ├── SnapManager.cs # 捕捉管理器
│ ├── EndPointSnap.cs # 端点捕捉
│ ├── MidPointSnap.cs # 中点捕捉
│ ├── CenterSnap.cs # 圆心捕捉
│ └── IntersectSnap.cs # 交点捕捉
├── PViewPort/ # 视口组件
│ ├── ViewportRenderer.cs # 视口渲染器
│ ├── ViewportManager.cs # 视口管理器
│ └── ZoomController.cs # 缩放控制器
└── ViewPortRtAction/ # 视口运行时动作
├── PanAction.cs # 平移动作
├── ZoomAction.cs # 缩放动作
└── RotateAction.cs # 旋转动作
关键特点:
- 完整的鼠标/键盘输入处理
- 精确的对象捕捉系统
- 视口的缩放、平移、旋转控制
- 夹点(Grip)编辑机制
3.2.6 第5层:应用运行时层(LightCAD.Runtime)
职责:提供高层应用逻辑和视图构建
模块结构:
LightCAD.Runtime/
├── ViewBuilder/ # 视图构建系统
│ ├── ViewBuilder.cs # 主构建器(71KB)
│ ├── ProjectioinProcessor.cs # 投影处理器(39KB)
│ ├── PolygonExt.cs # 多边形扩展(22KB)
│ ├── PrjResultCollector.cs # 投影结果收集
│ ├── BrepViewBuilder.cs # B-Rep视图构建
│ ├── GpuVisibleFilter.cs # GPU可见性过滤
│ ├── GlobalTopView/ # 全局俯视图
│ ├── ElevationView/ # 立面视图
│ ├── PlaneDetailView/ # 平面详图
│ ├── SectionView/ # 剖面视图
│ └── ProjectionApp/ # 投影应用框架
├── ViewportRuntime.cs # 视口运行时(119KB)
├── ElementAction.cs # 元素操作(43KB)
├── ComponentEditingObject.cs # 组件编辑对象
├── RefEditingObject.cs # 引用编辑对象
├── SectionEditingObject.cs # 截面编辑对象
└── ViewportEditingObject.cs # 视口编辑对象
关键特点:
- 包含最复杂的业务逻辑
- 视图构建器是核心组件(仅ViewBuilder.cs就有71KB)
- 支持多种视图类型生成
- 实现跨层级编辑能力
3.2.7 第6层:用户界面层
职责:提供最终用户交互界面
LightCAD.Model(Avalonia XAML控件):
LightCAD.Model/
├── ModelControl.axaml # 模型控件
├── ModelControl.axaml.cs # 模型控件后台代码
├── ModelEditor.axaml # 模型编辑器
├── ModelEditor.axaml.cs # 编辑器后台代码
├── ModelViewControl.axaml # 模型视图控件
├── ModelViewControl.axaml.cs # 视图控件后台代码
├── ModelStatusBar.axaml # 状态栏
└── ModelStatusBar.axaml.cs # 状态栏后台代码
LightCAD.WinForm(主应用程序):
LightCAD.WinForm/
├── Program.cs # 程序入口点
├── MainForm.cs # 主窗体
├── Font/ # 字体资源
│ ├── TTF/ # TrueType字体
│ │ ├── Roboto-Regular.ttf
│ │ ├── SimFang.ttf
│ │ ├── SimHei.ttf
│ │ └── SimSun.ttf
│ └── Shx/ # SHX CAD字体(50+种)
│ ├── simplex.shx
│ ├── txt.shx
│ ├── gbcbig.shx
│ └── ...
└── Resources/ # 其他资源文件
3.3 模块间通信机制
3.3.1 直接方法调用
最基本的通信方式——上层模块直接调用下层模块的公共API:
// Runtime层调用Core层的方法
var document = new LcDocument();
var line = new LcLine(new Point2d(0, 0), new Point2d(100, 100));
document.AddEntity(line);
3.3.2 事件驱动通信
通过事件系统实现松耦合的模块间通信:
// RenderUtils中的事件定义
public class RenderEvent
{
public event EventHandler<EntityChangedArgs> EntityChanged;
public event EventHandler<SelectionChangedArgs> SelectionChanged;
public event EventHandler ViewInvalidated;
}
// 上层订阅事件
renderEvent.EntityChanged += (sender, args) =>
{
// 处理实体变更
RefreshViewport();
};
3.3.3 接口契约
通过接口定义层间的交互契约:
// 在Core层定义接口
public interface IUpdateObject
{
void OnUpdate(UpdateContext context);
bool NeedsUpdate { get; }
}
// 在具体实体中实现
public class LcLine : LcEntity, IUpdateObject
{
public void OnUpdate(UpdateContext context)
{
// 更新逻辑
RecalculateBounds();
}
public bool NeedsUpdate { get; private set; }
}
3.3.4 依赖注入
LightCAD在某些模块中使用依赖注入来管理组件的创建和生命周期:
// 插件系统中的依赖注入
public class ComponentActionLoader
{
public void RegisterAction<T>(string name) where T : IComponentAction
{
// 注册组件操作
}
public IComponentAction ResolveAction(string name)
{
// 解析并返回操作实例
}
}
3.4 两种运行环境
3.4.1 完整编辑环境
在完整的编辑环境中,所有层次模块都参与工作:
用户操作 → WinForm → Model → Runtime → Drawing → RenderUtils → Core → MathLib
这是桌面应用程序的标准运行模式,提供完整的编辑和交互功能。
3.4.2 无头渲染环境
LightCAD还支持无编辑界面的渲染环境:
客户端程序 → RenderUtils → Core → MathLib
这种模式适用于:
- 服务端批量渲染
- 格式转换工具
- 自动化测试
- 嵌入式预览
在无头环境中,跳过了Drawing和Runtime层,直接使用RenderUtils的渲染能力。这是LightCAD架构的一个重要设计亮点。
3.5 扩展架构
3.5.1 插件体系
LightCAD的插件体系构建在分层架构之上,插件可以在不同层次上进行扩展:
┌─────────────────────────────────────────────────────────┐
│ 行业插件层 │
│ QdArch / QdElectric / QdHvac / QdStruct / QdWater │
├─────────────────────────────────────────────────────────┤
│ 组件操作层 │
│ LightCAD.Component.Actions │
├─────────────────────────────────────────────────────────┤
│ 核心框架层 │
│ MathLib → Core → RenderUtils → Drawing → Runtime │
└─────────────────────────────────────────────────────────┘
3.5.2 组件操作模块
LightCAD.Component.Actions模块实现了具体的3D建模操作:
// 操作加载器
public class ComponentActionLoader
{
// 动态加载操作
public void LoadActions(string pluginPath);
}
// 具体操作实现
public class CubeAction : IComponentAction
{
// 创建立方体的操作逻辑
}
public class ExtrudeAction : IComponentAction
{
// 拉伸操作逻辑(15KB)
}
public class LoftAction : IComponentAction
{
// 放样操作逻辑(40KB)
}
3.5.3 导入导出模块
LightCAD.ImportAndExport模块独立于核心层次结构,作为横切关注点存在:
LightCAD.ImportAndExport
├── DwgImporter.cs # DWG导入
├── DwgExporter.cs # DWG导出
├── DxfImporter.cs # DXF导入
├── DxfExporter.cs # DXF导出
├── SketchUpImporter.cs # SketchUp导入
└── NativeFormat.cs # 原生格式
3.6 核心设计决策分析
3.6.1 为什么选择分层架构
优势:
- 可维护性:每层代码量可控,修改影响范围有限
- 可测试性:每层可以独立进行单元测试
- 可复用性:底层模块(如MathLib)可以在其他项目中复用
- 团队协作:不同开发者可以并行开发不同层次的功能
设计权衡:
- 分层带来一定的性能开销(跨层调用)
- 需要严格遵守依赖规则
- 某些跨层功能的实现可能不够直观
3.6.2 RenderUtils独立成层的原因
将渲染工具独立为一层是LightCAD架构中的关键决策。根据框架设计备忘录的说明:
- Core层不适合直接用于无编辑环境的插件开发:因为Core依赖ThreeJs4Net(字体管理需要)
- WorkPlane3d的层次化问题:工作平面创建会引入ThreeJs4Net依赖
- 需要在Core和Runtime之间建立中间层:使得无编辑环境也能使用渲染功能
这个设计使得LightCAD可以灵活地支持多种运行模式。
3.6.3 混合UI框架的选择
WinForms + Avalonia的组合也是经过深思熟虑的选择:
- WinForms提供稳定的窗口管理和Windows平台原生集成
- Avalonia提供现代化的XAML声明式UI和数据绑定
- 这种混合方案在保持与Windows原生功能兼容的同时,享受了现代UI框架的开发效率
3.7 数据流分析
3.7.1 创建实体的数据流
用户操作(UI层)
↓
命令解析(Runtime层)
↓
创建实体对象(Core层)
↓
几何计算(MathLib层)
↓
注册到文档(Core层)
↓
触发更新事件(RenderUtils层)
↓
重新渲染视口(Drawing层)
↓
更新UI显示(UI层)
3.7.2 渲染管线数据流
实体数据(Core层)
↓
构建Three.js场景对象(RenderUtils层)
↓
设置材质和光照(RenderUtils层)
↓
投影计算(Runtime层 ViewBuilder)
↓
视口剪裁和可见性判断(Drawing层)
↓
GPU渲染输出(Three.js/OpenTK)
↓
屏幕显示(UI层)
3.7.3 文件导入数据流
读取DWG/DXF文件(ImportAndExport模块)
↓
解析文件结构(netDxf/ODA SDK)
↓
转换为LightCAD实体(Core层)
↓
几何数据转换(MathLib层)
↓
添加到文档(Core层)
↓
触发重新渲染(RenderUtils层)
↓
显示在视口中(Drawing层 → UI层)
3.8 与FY_Layout的关系
3.8.1 框架与应用的关系
LightCAD是底层CAD框架,FY_Layout是基于LightCAD开发的场地布置应用:
┌───────────────────────────────┐
│ FY_Layout(应用层) │
│ 场布设计/板房系统/道路设计 │
├───────────────────────────────┤
│ LightCAD(框架层) │
│ CAD核心/渲染/绘图/运行时 │
└───────────────────────────────┘
FY_Layout展示了如何基于LightCAD框架进行行业应用的二次开发,是学习LightCAD扩展开发的最佳参考实例。
3.8.2 扩展点
FY_Layout主要在以下层次上扩展LightCAD:
- Core层:定义新的场布元素类型
- Runtime层:实现场布特有的操作逻辑
- UI层:提供场布设计的专用界面
- Plugin层:通过插件系统注册场布功能
3.9 本章小结
本章深入分析了LightCAD的核心架构和分层设计。LightCAD采用6层分层架构,从底层的数学库到顶层的用户界面,每一层职责明确、依赖清晰。通过事件驱动、接口契约和依赖注入等机制实现模块间的松耦合通信。独特的RenderUtils中间层设计使得LightCAD可以灵活支持完整编辑环境和无头渲染两种运行模式。这种架构设计为插件开发和行业定制提供了坚实的基础。
上一章:第二章:开发环境搭建与项目配置
下一章:第四章:数学库详解