核心架构与模块设计
第三章:核心架构与模块设计
3.1 LightCAD框架架构
3.1.1 整体架构
LightCAD采用分层架构设计,从底层到上层依次为:
┌─────────────────────────────────────────────────────────────┐
│ UI Layer (用户界面层) │
│ WinForms | Avalonia | Ribbon | DockPanel | PropertyGrid │
├─────────────────────────────────────────────────────────────┤
│ Runtime Layer (运行时层) │
│ AppRuntime | DocumentRuntime | CommandSystem | Plugin │
├─────────────────────────────────────────────────────────────┤
│ Drawing Layer (绘图层) │
│ Canvas2d | Canvas3d | SkiaSharp | ThreeJs4Net │
├─────────────────────────────────────────────────────────────┤
│ Model Layer (模型层) │
│ Component | Parameter | Provider | Definition │
├─────────────────────────────────────────────────────────────┤
│ Core Layer (核心层) │
│ Document | Element | Transaction | Layer | Style │
├─────────────────────────────────────────────────────────────┤
│ Math Layer (数学层) │
│ Vector | Matrix | Geometry | CSG | Intersect │
└─────────────────────────────────────────────────────────────┘
3.1.2 核心概念
| 概念 | 类名 | 说明 |
|---|---|---|
| 文档 | LcDocument | CAD文档,包含所有元素和设置 |
| 元素 | LcElement | 图形元素基类 |
| 图层 | LcLayer | 图层管理 |
| 事务 | Transaction | 撤销/重做支持 |
| 运行时 | DocumentRuntime | 文档运行时环境 |
| 视口 | Viewport | 视图管理 |
3.1.3 命名空间结构
LightCAD
├── Core # 核心模块
│ ├── LcDocument # 文档类
│ ├── LcElement # 元素基类
│ ├── ElementType # 元素类型定义
│ ├── LcLayer # 图层类
│ ├── LcGuid # GUID类型
│ └── Elements/ # 内置元素类型
├── MathLib # 数学库
│ ├── Vector2/Vector3 # 向量
│ ├── Matrix3/Matrix4 # 矩阵
│ ├── Box2/Box3 # 包围盒
│ ├── Curve2d/Curve3d # 曲线
│ ├── Polyline2d # 多段线
│ ├── Color # 颜色
│ └── Csg/ # CSG运算
├── Drawing # 绘图模块
│ ├── LcCanvas2d # 2D画布
│ ├── LcPaint # 画笔
│ └── LcTextPaint # 文字画笔
├── Drawing.Actions # 操作模块
│ ├── ElementAction # 元素操作基类
│ ├── DirectComponentAction # 直接组件操作
│ ├── PointInputer # 点输入器
│ └── Action/ # 内置操作
├── Model # 模型模块
│ ├── DirectComponent # 直接组件
│ ├── LcComponentDefinition # 组件定义
│ └── LcParameterSet # 参数集
└── Runtime # 运行时
├── AppRuntime # 应用运行时
├── DocumentRuntime # 文档运行时
├── ILcPlugin # 插件接口
└── CommandClass # 命令特性
3.2 FY_Layout模块架构
3.2.1 模块总览
FY_Layout包含两个主要项目:
FY_Layout
├── QdLayout # 主插件项目
│ ├── 插件入口(LayoutPlugin)
│ ├── 命令系统(LayoutCmds)
│ ├── 元素类型(LayoutElementType)
│ └── 场布模块(各功能模块)
└── QdLayoutProvider # Provider项目
└── 三维模型生成器
3.2.2 QdLayout项目结构
QdLayout/
├── LayoutPlugin.cs # 插件入口,实现ILcPlugin
├── LayoutCmds.cs # 命令定义类
├── LayoutElementType.cs # 元素类型静态定义
├── LcCurveChangeLoop.cs # 曲线闭合工具类
├── GlobalUsing.cs # 全局using声明
│
├── Barrier/ # 防护栏杆模块
│ ├── QdBarrier.cs # 元素类
│ ├── BarrierAction.cs # 二维操作类
│ └── Barrier3dAction.cs # 三维操作类
│
├── Berm/ # 出土道路模块
│ ├── QdBerm.cs
│ ├── QdBermDef.cs # 定义类
│ ├── BermAction.cs
│ └── Berm3dAction.cs
│
├── Earthwork/ # 土方回填模块
├── Equipment/ # 设备模块
├── Fence/ # 围栏模块
├── FoundationPit/ # 基坑模块
├── Ground/ # 硬化地面模块
├── Harden/ # 路面硬化模块
├── Lawn/ # 草坪模块
├── OpenLine/ # 开门边线模块
├── PlanBuild/ # 拟建建筑模块
├── PlateHouse/ # 板房模块
├── PropertyLine/ # 用地红线模块
├── Road/ # 道路模块
├── Site/ # 场地模块
├── TemplateArrange/ # 模板排布模块
│
├── Properties/ # 项目属性
│ ├── Resources.resx # 资源文件
│ └── Resources.Designer.cs
└── Resources/ # 资源文件(图标等)
3.2.3 单个功能模块结构
以草坪(Lawn)模块为例,展示标准的模块结构:
Lawn/
├── QdLawn.cs # 元素类,继承DirectComponent
├── QdLawnDef.cs # 定义类,继承组件定义
├── LawnAction.cs # 二维操作类,继承DirectComponentAction
└── Lawn3dAction.cs # 三维操作类,处理三维渲染
类职责说明:
| 类名 | 基类 | 职责 |
|---|---|---|
| QdLawn | DirectComponent | 数据模型,存储元素属性和几何数据 |
| QdLawnDef | LcComponentDefinition | 元素定义,提供默认参数和配置 |
| LawnAction | DirectComponentAction | 二维操作,处理绘制、编辑、夹点等 |
| Lawn3dAction | IElement3dAction | 三维操作,生成三维模型 |
3.3 插件入口类详解
3.3.1 ILcPlugin接口
public interface ILcPlugin
{
void InitUI(); // UI初始化
void Loaded(); // 插件加载
void Completed(); // 完成加载
void OnInitializeDocRt(DocumentRuntime docRt); // 文档初始化
void OnDisposeDocRt(DocumentRuntime docRt); // 文档销毁
}
3.3.2 LayoutPlugin实现分析
namespace QdLayout
{
public class LayoutPlugin : ILcPlugin
{
// 静态TabItem定义:创建"场布"选项卡的UI结构
public static TabItem LayoutItem = new TabItem
{
Name = "LayoutMajor",
Text = "场布",
ShortcutKey = "ALT-L",
ButtonGroups = new List<TabButtonGroup>
{
new TabButtonGroup
{
Buttons = new List<TabButton>
{
// 创建项目按钮
new TabButton
{
Name = "CreateProject",
Text = "创建项目",
Icon = Properties.Resources.创建项目,
IsCommand = true,
},
// 草坪按钮(带下拉菜单)
new TabButton
{
Name = "Lawn",
Text = "草坪",
Icon = Properties.Resources.草地,
IsCommand = true,
DropDowns = new List<TabButton>
{
new TabButton { Name = "Lawn", Text = "任意绘制", ... },
new TabButton { Name = "LawnRec", Text = "矩形绘制", ... },
new TabButton { Name = "LawnChange", Text = "转换多段线", ... },
}
},
// 其他按钮...
}
}
}
};
public void InitUI()
{
// UI初始化阶段(在Loaded之后调用)
}
public void Loaded()
{
// 1. 注册元素类型
LcDocument.RegistElementTypes(LayoutElementType.All);
// 2. 注册程序集
LcRuntime.RegistAssemblies.Add("QdLayout");
// 3. 注册元素操作类(二维)
LcDocument.ElementActions.Add(LayoutElementType.Lawn, new LawnAction());
LcDocument.ElementActions.Add(LayoutElementType.Fence, new FenceAction());
LcDocument.ElementActions.Add(LayoutElementType.FoundationPit, new FoundationPitAction());
// ... 更多元素操作注册
// 4. 注册三维操作类
LcDocument.Element3dActions.Add(LayoutElementType.Lawn, new Lawn3dAction());
LcDocument.Element3dActions.Add(LayoutElementType.Fence, new Fence3dAction());
// ... 更多三维操作注册
// 5. 初始化其他配置
PlateRoomConfigManager.Init();
}
public void Completed()
{
// 将TabItem添加到主界面
AppRuntime.UISystem.AddInitTabItems([LayoutItem]);
}
public void OnInitializeDocRt(DocumentRuntime docRt)
{
// 每个文档初始化时调用
}
public void OnDisposeDocRt(DocumentRuntime docRt)
{
// 每个文档关闭时调用
}
}
}
3.3.3 插件生命周期
应用程序启动
│
▼
扫描并加载插件DLL
│
▼
创建ILcPlugin实例
│
▼
调用 Loaded() ← 注册元素类型、操作类
│
▼
调用 InitUI() ← UI初始化
│
▼
调用 Completed() ← 添加UI元素
│
▼
┌────────────────────────┐
│ 应用程序运行中 │
│ │ │
│ ▼ │
│ 用户打开新文档 │
│ │ │
│ ▼ │
│ OnInitializeDocRt() │
│ │ │
│ ▼ │
│ 用户关闭文档 │
│ │ │
│ ▼ │
│ OnDisposeDocRt() │
└────────────────────────┘
│
▼
应用程序关闭
3.4 元素类型系统
3.4.1 ElementType定义
// LayoutElementType.cs
public static class LayoutElementType
{
// 草坪元素类型
public static ElementType Lawn = new ElementType
{
Guid = Guid.ParseExact("{63A566EA-3702-A98C-7A6B-8DBEA6B3F41A}", "B").ToLcGuid(),
Name = "Lawn",
DispalyName = "草坪",
ClassType = typeof(QdLawn)
};
// 基坑元素类型
public static ElementType FoundationPit = new ElementType
{
Guid = Guid.ParseExact("{C082E6EA-E099-94AB-50FA-50DF72D286D4}", "B").ToLcGuid(),
Name = "FoundationPit",
DispalyName = "基坑",
ClassType = typeof(QdFoundationPit)
};
// 围栏元素类型
public static ElementType Fence = new ElementType
{
Guid = Guid.ParseExact("{5A9EC5E6-09BF-4DB3-9AD2-DD0DA74F099A}", "B").ToLcGuid(),
Name = "Fence",
DispalyName = "围墙",
ClassType = typeof(QdFence)
};
// ... 其他元素类型定义
// 所有元素类型数组(用于批量注册)
public static ElementType[] All = new ElementType[]
{
Lawn, FoundationPit, Road, Earthwork, Berm,
Harden, Site, PropertyLine, Fence, PlateBuilding,
PlateBuildGroup, OpenLine
};
}
3.4.2 ElementType属性说明
| 属性 | 类型 | 说明 |
|---|---|---|
| Guid | LcGuid | 唯一标识符,全局唯一 |
| Name | string | 内部名称,用于代码引用 |
| DispalyName | string | 显示名称,用于UI显示 |
| ClassType | Type | 元素类的类型信息 |
3.4.3 GUID格式说明
// "B"格式:带大括号和连字符
Guid.ParseExact("{63A566EA-3702-A98C-7A6B-8DBEA6B3F41A}", "B")
// 其他格式:
// "D":带连字符,无大括号 63A566EA-3702-A98C-7A6B-8DBEA6B3F41A
// "N":32位数字 63A566EA3702A98C7A6B8DBEA6B3F41A
// "P":带括号 (63A566EA-3702-A98C-7A6B-8DBEA6B3F41A)
3.5 命令系统
3.5.1 CommandClass特性
[CommandClass]
public class LayoutCmds
{
// 命令方法定义
}
3.5.2 CommandMethod特性
[CommandMethod(Name = "Lawn", ShortCuts = "LW")]
public CommandResult DrawLawn(IDocumentEditor docEditor, string[] args)
{
var lawnAction = new LawnAction(docEditor);
lawnAction.ExecCreatePoly(args);
return CommandResult.Succ();
}
特性参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| Name | string | 命令名称,用于命令行调用 |
| ShortCuts | string | 快捷键或简写 |
3.5.3 命令方法签名
public CommandResult MethodName(IDocumentEditor docEditor, string[] args)
- 返回值:
CommandResult,表示命令执行结果 - 参数:
IDocumentEditor docEditor:文档编辑器接口string[] args:命令参数数组
3.5.4 LayoutCmds完整分析
[CommandClass]
public class LayoutCmds
{
// 围栏命令
[CommandMethod(Name = "Fence", ShortCuts = "W")]
public CommandResult DrawFence(IDocumentEditor docEditor, string[] args)
{
var fenceAction = new FenceAction(docEditor);
fenceAction.ExecCreate(args);
return CommandResult.Succ();
}
// 草坪命令 - 任意绘制
[CommandMethod(Name = "Lawn", ShortCuts = "LW")]
public CommandResult DrawLawn(IDocumentEditor docEditor, string[] args)
{
var lawnAction = new LawnAction(docEditor);
lawnAction.ExecCreatePoly(args); // 任意多边形绘制
return CommandResult.Succ();
}
// 草坪命令 - 矩形绘制
[CommandMethod(Name = "LawnRec", ShortCuts = "LWRC")]
public CommandResult DrawLawnRec(IDocumentEditor docEditor, string[] args)
{
var lawnAction = new LawnAction(docEditor);
lawnAction.ExecCreateRec(args); // 矩形绘制
return CommandResult.Succ();
}
// 草坪命令 - 转换多段线
[CommandMethod(Name = "LawnChange", ShortCuts = "LWCH")]
public CommandResult DrawLawnChange(IDocumentEditor docEditor, string[] args)
{
var lawnAction = new LawnAction(docEditor);
lawnAction.ExecCreate(args); // 从现有线段转换
return CommandResult.Succ();
}
// 基坑命令
[CommandMethod(Name = "FoundationPit", ShortCuts = "FDP")]
public CommandResult DrawFoundationPit(IDocumentEditor docEditor, string[] args)
{
var fdpAction = new FoundationPitAction(docEditor);
fdpAction.ExecCreatePoly(args);
return CommandResult.Succ();
}
// 道路命令
[CommandMethod(Name = "Road", ShortCuts = "ROD")]
public CommandResult DrawRoad(IDocumentEditor docEditor, string[] args)
{
var roadAction = new RoadAction(docEditor);
roadAction.ExecCreate(args);
return CommandResult.Succ();
}
// ... 更多命令
}
3.6 配置与设置
3.6.1 QdLayoutCategorySettings
public static class QdLayoutCategorySettings
{
// 命名空间键,用于组件分类
public static string NamespaceKey = "场布施工设计";
// 使用类型
public static string UseType = "设计";
// FromType转换方法
public static void CnovertFromtype(ref FromType fromtype, out string convertLabel)
{
if (fromtype == FromType.Library)
{
fromtype = FromType.Document;
convertLabel = "转到文档中";
}
else
{
fromtype = FromType.Library;
convertLabel = "转到构件库中";
}
}
public static string FromTypeMessage(FromType fromtype)
{
return fromtype == FromType.Library ? "转到文档中" : "转到构件库中";
}
}
3.6.2 全局配置使用
在GlobalUsing.cs中使用静态导入:
global using static QdLayout.QdLayoutCategorySettings;
这样可以在代码中直接使用NamespaceKey等静态成员:
// 获取组件定义
var lawnDef = docRt.GetUseComDef($"{NamespaceKey}.绿色文明", "草坪", null);
3.7 模块间关系
3.7.1 依赖关系图
┌─────────────────┐
│ LayoutPlugin │
│ (插件入口) │
└────────┬────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ LayoutCmds │ │LayoutElementType│ │ 场布功能模块 │
│ (命令系统) │ │ (类型定义) │ │ (Lawn等) │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
└───────────────────┼───────────────────┘
▼
┌─────────────────┐
│ LightCAD │
│ 核心框架 │
└─────────────────┘
3.7.2 数据流向
用户操作(命令/鼠标)
│
▼
LayoutCmds 命令入口
│
▼
XxxAction 操作类(如LawnAction)
│
┌────┴────┐
▼ ▼
创建/编辑 绘制
│ │
▼ ▼
QdXxx LcCanvas2d 元素类/画布
│
▼
LcDocument 文档存储
3.8 扩展机制
3.8.1 添加新元素类型
-
定义ElementType
public static ElementType NewElement = new ElementType { Guid = Guid.NewGuid().ToLcGuid(), Name = "NewElement", DispalyName = "新元素", ClassType = typeof(QdNewElement) }; -
创建元素类
public class QdNewElement : DirectComponent { // 属性和方法... } -
创建操作类
public class NewElementAction : DirectComponentAction { // 绘制、编辑逻辑... } -
注册元素和操作
// 在Loaded()中 LcDocument.ElementActions.Add(LayoutElementType.NewElement, new NewElementAction());
3.8.2 添加新命令
// 在LayoutCmds中添加
[CommandMethod(Name = "NewCommand", ShortCuts = "NC")]
public CommandResult NewCommand(IDocumentEditor docEditor, string[] args)
{
// 命令逻辑
return CommandResult.Succ();
}
3.8.3 添加新UI元素
// 在TabItem定义中添加按钮
new TabButton
{
Name = "NewCommand",
Text = "新功能",
Icon = Properties.Resources.新图标,
IsCommand = true,
}
3.9 本章小结
本章详细介绍了FY_Layout的核心架构与模块设计:
- LightCAD框架架构:分层设计,各层职责清晰
- FY_Layout模块结构:QdLayout和QdLayoutProvider两个项目
- 插件入口类:ILcPlugin接口实现和生命周期
- 元素类型系统:ElementType的定义和注册
- 命令系统:CommandClass和CommandMethod特性的使用
- 配置管理:全局设置和命名空间管理
- 扩展机制:如何添加新元素、命令和UI
理解了核心架构后,下一章我们将深入学习插件开发的基础知识。

浙公网安备 33010602011771号