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

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
腾讯CDC
G
Google Developers Blog
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
有赞技术团队
有赞技术团队
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
美团技术团队
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志

博客园 - 我才是银古

第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建模操作,是建模扩展的核心入口。


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

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