惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
宝玉的分享
宝玉的分享
月光博客
月光博客
B
Blog
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
N
Netflix TechBlog - Medium
博客园_首页
GbyAI
GbyAI
人人都是产品经理
人人都是产品经理
A
About on SuperTechFans
Y
Y Combinator Blog
L
LangChain Blog
有赞技术团队
有赞技术团队
D
Docker
爱范儿
爱范儿
博客园 - 司徒正美
H
Hackread – Cybersecurity News, Data Breaches, AI and More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
D
DataBreaches.Net

博客园 - 我才是银古

第16章:常见问题、排错与最佳实践 第15章:扩展生态、MCAD 与外部集成 第12章:实战案例:机械结构与 3D 打印零件 第14章:构建、测试、调试与贡献流程 第13章:OpenSCAD 源码架构与核心执行流程 第11章:预览、渲染、网格精度与性能优化 第09章:列表推导、递归与算法建模 第08章:参数化零件库与复用设计 第10章:导入导出、命令行与自动化 第06章:CSG 布尔建模方法 第07章:二维图形、拉伸、旋转与投影 第05章:基础几何、坐标系与变换 第04章:参数、变量、函数、模块与作用域 OpenSCAD 教程目录 第03章:OpenSCAD 语言基础 第02章:安装、环境配置与开发工作流 第01章:OpenSCAD 项目全景与学习路线 第02章:源码获取、编译与开发环境配置 第01章:OCCT项目全景与学习路线 第18章:二次开发实战与综合案例 第18章:综合实战案例 第17章:数据交换与协同 第16章:源码架构与二次开发 第15章:插件与自定义工作台开发 第14章:Python脚本宏与自动化 第13章:FEM仿真分析 第12章:CAM数控加工 第11章:SurfaceMesh与逆向工程 第10章:Draft二维绘图与BIM建筑 第09章:工程图TechDraw
插件系统与扩展开发
我才是银古 · 2026-06-20 · via 博客园 - 我才是银古

第十五章:插件系统与扩展开发

15.1 插件系统概述

15.1.1 Weikio Plugin Framework

LightCAD的插件系统基于Weikio Plugin Framework构建,这是一个.NET平台的轻量级插件加载框架,支持运行时动态加载和卸载程序集。

15.1.2 内置行业插件

LightCAD预置了五个行业插件:

插件 文件 大小 功能领域
QdArch QdArch.dll 591KB 建筑设计
QdElectric QdElectric.dll 45KB 电气设计
QdHvac QdHvac.dll 95KB 暖通设计
QdStruct QdStruct.dll 173KB 结构设计
QdWater QdWater.dll 201KB 给排水设计

15.2 插件加载机制

15.2.1 插件管理器

public class PluginManager
{
    private static List<IPlugin> loadedPlugins = new();
    private static string pluginDirectory;

    /// <summary>
    /// 加载指定目录下的所有插件
    /// </summary>
    public static void LoadPlugins(string directory)
    {
        pluginDirectory = directory;

        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
            return;
        }

        var pluginFiles = Directory.GetFiles(directory, "*.dll");

        foreach (var pluginFile in pluginFiles)
        {
            try
            {
                LoadPlugin(pluginFile);
            }
            catch (Exception ex)
            {
                Console.WriteLine(
                    $"加载插件失败 {Path.GetFileName(pluginFile)}: {ex.Message}");
            }
        }
    }

    /// <summary>
    /// 加载单个插件
    /// </summary>
    private static void LoadPlugin(string pluginPath)
    {
        // 使用Weikio Plugin Framework加载
        var assembly = Assembly.LoadFrom(pluginPath);

        // 查找实现IPlugin接口的类型
        var pluginTypes = assembly.GetTypes()
            .Where(t => typeof(IPlugin).IsAssignableFrom(t)
                && !t.IsAbstract && !t.IsInterface);

        foreach (var pluginType in pluginTypes)
        {
            var plugin = (IPlugin)Activator.CreateInstance(pluginType);
            plugin.Initialize();
            loadedPlugins.Add(plugin);

            Console.WriteLine($"已加载插件:{plugin.Name} v{plugin.Version}");
        }
    }

    /// <summary>
    /// 获取所有已加载的插件
    /// </summary>
    public static IReadOnlyList<IPlugin> LoadedPlugins => loadedPlugins;

    /// <summary>
    /// 卸载所有插件
    /// </summary>
    public static void UnloadAll()
    {
        foreach (var plugin in loadedPlugins)
        {
            plugin.Shutdown();
        }
        loadedPlugins.Clear();
    }
}

15.2.2 插件接口

/// <summary>
/// 插件基础接口
/// </summary>
public interface IPlugin
{
    /// <summary>
    /// 插件名称
    /// </summary>
    string Name { get; }

    /// <summary>
    /// 插件版本
    /// </summary>
    string Version { get; }

    /// <summary>
    /// 插件描述
    /// </summary>
    string Description { get; }

    /// <summary>
    /// 插件作者
    /// </summary>
    string Author { get; }

    /// <summary>
    /// 初始化插件
    /// </summary>
    void Initialize();

    /// <summary>
    /// 关闭插件
    /// </summary>
    void Shutdown();
}

/// <summary>
/// 带命令注册能力的插件
/// </summary>
public interface ICommandPlugin : IPlugin
{
    /// <summary>
    /// 注册插件命令
    /// </summary>
    void RegisterCommands(CommandRegistry registry);
}

/// <summary>
/// 带UI扩展能力的插件
/// </summary>
public interface IUIPlugin : IPlugin
{
    /// <summary>
    /// 注册菜单项
    /// </summary>
    void RegisterMenuItems(MenuRegistry registry);

    /// <summary>
    /// 注册工具栏按钮
    /// </summary>
    void RegisterToolbarItems(ToolbarRegistry registry);

    /// <summary>
    /// 注册面板
    /// </summary>
    void RegisterPanels(PanelRegistry registry);
}

/// <summary>
/// 带元素类型扩展能力的插件
/// </summary>
public interface IElementPlugin : IPlugin
{
    /// <summary>
    /// 注册自定义元素类型
    /// </summary>
    void RegisterElementTypes(ElementTypeRegistry registry);
}

15.3 开发自定义插件

15.3.1 创建插件项目

# 创建类库项目
dotnet new classlib -n MyLightCADPlugin -f net10.0-windows

# 添加LightCAD核心引用
cd MyLightCADPlugin
dotnet add reference ../LightCAD.Core/LightCAD.Core.csproj
dotnet add reference ../LightCAD.Runtime/LightCAD.Runtime.csproj

15.3.2 实现插件

// MyPlugin.cs
public class MyPlugin : IPlugin, ICommandPlugin, IElementPlugin
{
    public string Name => "我的自定义插件";
    public string Version => "1.0.0";
    public string Description => "LightCAD自定义插件示例";
    public string Author => "开发者";

    public void Initialize()
    {
        Console.WriteLine("我的插件已初始化");
    }

    public void Shutdown()
    {
        Console.WriteLine("我的插件已关闭");
    }

    public void RegisterCommands(CommandRegistry registry)
    {
        registry.Register(new CommandInfo
        {
            Name = "MYCOMMAND",
            DisplayName = "我的命令",
            Description = "执行自定义操作",
            Action = ExecuteMyCommand
        });

        registry.Register(new CommandInfo
        {
            Name = "DRAWSTAR",
            DisplayName = "绘制星形",
            Description = "绘制一个正五角星",
            Action = DrawStar
        });
    }

    public void RegisterElementTypes(ElementTypeRegistry registry)
    {
        registry.Register(new ElementType
        {
            Guid = new LcGuid("my-plugin-star-element"),
            Name = "Star",
            DisplayName = "五角星",
            Category = "自定义图形",
            Is3D = false,
            Creator = () => new StarElement()
        });
    }

    private void ExecuteMyCommand()
    {
        // 自定义命令逻辑
        MessageBox.Show("执行自定义命令!");
    }

    private void DrawStar()
    {
        // 绘制五角星的逻辑
        var center = InputManager.GetPoint("指定五角星中心:");
        var radius = InputManager.GetDistance("指定外径:");

        var star = CreateStarPolyline(center, radius, 5);
        DocumentManager.Current.Entities.Add(star);
    }

    private LcPolyline CreateStarPolyline(Point2d center,
                                           double outerRadius, int points)
    {
        var polyline = new LcPolyline { IsClosed = true };
        var innerRadius = outerRadius * 0.382;

        for (int i = 0; i < points * 2; i++)
        {
            var angle = Math.PI / 2 + Math.PI * i / points;
            var r = (i % 2 == 0) ? outerRadius : innerRadius;
            polyline.AddVertex(new Point2d(
                center.X + r * Math.Cos(angle),
                center.Y + r * Math.Sin(angle)
            ));
        }

        return polyline;
    }
}

15.3.3 自定义元素类型

/// <summary>
/// 自定义五角星元素
/// </summary>
public class StarElement : LcEntity, IUpdateObject
{
    public Point2d Center { get; set; }
    public double OuterRadius { get; set; } = 50;
    public double InnerRadius { get; set; } = 19.1;
    public int Points { get; set; } = 5;
    public double Rotation { get; set; } = 0;

    public override string TypeName => "Star";

    public override BoundingBox2d Bounds
    {
        get
        {
            return new BoundingBox2d
            {
                Min = new Point2d(
                    Center.X - OuterRadius, Center.Y - OuterRadius),
                Max = new Point2d(
                    Center.X + OuterRadius, Center.Y + OuterRadius)
            };
        }
    }

    public override void TransformBy(Matrix4d matrix)
    {
        var p3d = new Point3d(Center.X, Center.Y, 0);
        var transformed = matrix.Transform(p3d);
        Center = new Point2d(transformed.X, transformed.Y);
    }

    public override LcEntity Clone()
    {
        return new StarElement
        {
            Center = Center,
            OuterRadius = OuterRadius,
            InnerRadius = InnerRadius,
            Points = Points,
            Rotation = Rotation,
            Color = Color,
            LayerName = LayerName
        };
    }

    public override double DistanceTo(Point2d point)
    {
        return point.DistanceTo(Center) - OuterRadius;
    }

    /// <summary>
    /// 获取五角星的顶点
    /// </summary>
    public List<Point2d> GetVertices()
    {
        var vertices = new List<Point2d>();
        for (int i = 0; i < Points * 2; i++)
        {
            var angle = Rotation + Math.PI / 2 + Math.PI * i / Points;
            var r = (i % 2 == 0) ? OuterRadius : InnerRadius;
            vertices.Add(new Point2d(
                Center.X + r * Math.Cos(angle),
                Center.Y + r * Math.Sin(angle)
            ));
        }
        return vertices;
    }

    public bool NeedsUpdate { get; private set; }
    public void OnUpdate(UpdateContext context)
    {
        NeedsUpdate = false;
    }
}

15.4 插件部署

15.4.1 编译和部署

# 编译插件
dotnet build -c Release

# 将编译输出复制到LightCAD的Plugins目录
copy bin/Release/net10.0-windows/MyLightCADPlugin.dll \
     ../LightCAD.WinForm/bin/Debug/net10.0-windows/Plugins/

15.4.2 插件清单文件

为了更好地管理插件信息,可以创建清单文件:

{
    "name": "MyLightCADPlugin",
    "version": "1.0.0",
    "author": "开发者",
    "description": "LightCAD自定义插件示例",
    "assembly": "MyLightCADPlugin.dll",
    "dependencies": [],
    "minimumLightCADVersion": "1.0.0"
}

15.5 ComponentActionLoader

15.5.1 操作加载器

ComponentActionLoader是LightCAD中专门用于加载建模操作的插件加载器:

public class ComponentActionLoader
{
    private Dictionary<string, IComponentAction> actions = new();

    /// <summary>
    /// 从程序集加载操作
    /// </summary>
    public void LoadActionsFromAssembly(Assembly assembly)
    {
        var actionTypes = assembly.GetTypes()
            .Where(t => typeof(IComponentAction).IsAssignableFrom(t)
                && !t.IsAbstract);

        foreach (var type in actionTypes)
        {
            var action = (IComponentAction)Activator.CreateInstance(type);
            actions[action.Name] = action;
        }
    }

    /// <summary>
    /// 获取操作
    /// </summary>
    public IComponentAction GetAction(string name)
    {
        return actions.TryGetValue(name, out var action) ? action : null;
    }

    /// <summary>
    /// 获取所有操作
    /// </summary>
    public IEnumerable<IComponentAction> GetAllActions()
    {
        return actions.Values;
    }

    /// <summary>
    /// 获取某个类别的操作
    /// </summary>
    public IEnumerable<IComponentAction> GetActionsByCategory(string category)
    {
        return actions.Values.Where(a => a.Category == category);
    }
}

public interface IComponentAction
{
    string Name { get; }
    string DisplayName { get; }
    string Category { get; }
    LcSolid3d Execute(ActionContext context);
}

15.6 扩展点总结

15.6.1 LightCAD可扩展的维度

扩展维度 接口/机制 说明
元素类型 IElementPlugin / ElementTypeRegistry 定义新的图元类型
命令 ICommandPlugin / CommandRegistry 添加新的用户命令
建模操作 IComponentAction / ComponentActionLoader 添加3D建模操作
UI菜单 IUIPlugin / MenuRegistry 扩展菜单系统
UI工具栏 IUIPlugin / ToolbarRegistry 添加工具栏按钮
UI面板 IUIPlugin / PanelRegistry 添加侧边面板
文件格式 IFormatPlugin / FormatConverter 支持新的文件格式
捕捉类型 ISnapProvider / SnapManager 自定义捕捉行为

15.7 本章小结

本章详细介绍了LightCAD的插件系统和扩展开发方法。LightCAD基于Weikio Plugin Framework提供了灵活的插件加载机制,支持运行时动态加载插件。通过IPlugin及其扩展接口(ICommandPlugin、IElementPlugin、IUIPlugin),开发者可以在多个维度上扩展LightCAD的功能。内置的五个行业插件展示了实际的插件应用场景。ComponentActionLoader专门用于加载3D建模操作,是建模扩展的核心入口。


上一章第十四章:文件格式与数据交换

下一章第十六章:命令与操作系统