夜雨聆风学习资料网

ARTICLE · 1048985

实战|用 AI 写 CAD 插件:一键画层板(附源码+提示词)

实战|用 AI 写 CAD 插件:一键画层板(附源码+提示词)
这是《零基础 CAD 插件从 0 到 1》第 6 篇

上一篇我们把门板铰链孔跑通了,后台有读者留言:“层板能不能也搞一个?每次等分算半天。”

能。这一篇就写:一键画层板

先看效果

以前画层板,我是这么干的:

  1. 量区域内的高度

  2. 然后还要看区域高度计算几块层板

  3. 算出层板间隔

  4. 画出第一块层板

  5. 然后复制

  6. 画完然后标注尺寸

如果是鞋柜一个柜子好几个区域都要算,非常的麻烦。

当我写好插件后是这样的:

输入命令 DrawShelf → 点柜体内框 → 输入层板数量 → 自动等分画线。

图层自动创建,颜色自动设置,一秒钟搞定。

我们需要CAD帮干什么样的活

怎么给AI写提示词:

1,告诉AI你使用的环境比如说编程语言和cad的版本

2,告诉AI你需要实现的功能

3,告诉AI你是0编程经验的新手让它直接给出完整可编译的源码Q

看我的的提示词:

今天我需要写一个一键画层板的CAD插件,要求是用C# .net4.8  

功能需求: 

1,交互流程为,用户输入命令DrawShelf --->用户点选矩形内部或者是选择4条线组成的矩形--->然后默认居中画出层板--->画完后命令提示画了几个层板。 

2,要求层板数量可以增加输入W为+S为- 

3,层板需要做出实时预览 

4,矩形框要有高亮显示,高亮显示需要在绘制完成之后取消 

5,因为用户水平不一所以你需要处理区域,有可能是矩形,也有可能不是封闭图形,也有可能是几条线段,所以你需要设置封闭阈值等等因素 

6,层板厚度默认为18,用户可以自己设置厚度 

请你帮我写出完整代码,我直接可复制编译的代码。

这段提示词可以直接复制去问 AI。重点就是:命令名、交互流程、需要的功能,全部写清楚。

AI 给我的代码(核心部分)

AI 生成之后,我做了修改和适配。完整代码如下:

using System;using System.Collections.Generic;using System.Linq;using Autodesk.AutoCAD.ApplicationServices;using Autodesk.AutoCAD.DatabaseServices;using Autodesk.AutoCAD.EditorInput;using Autodesk.AutoCAD.Geometry;using Autodesk.AutoCAD.Runtime;[assembly: CommandClass(typeof(DrawShelfPlugin.DrawShelfCmd))]namespace DrawShelfPlugin{    public class DrawShelfCmd    {        // 配置参数        private const double DefaultThickness = 18.0;        private const double CloseTolerance = 1e-3// 封闭阈值        private const double PickTol = 1e-2;        private Document _doc;        private Editor _ed;        private Database _db;        private Polyline _highlightPoly; // 高亮框        private int _shelfCount = 1;     // 当前层数        private double _shelfThick = DefaultThickness;        private Point3d _insPoint;        private bool _isValidRect = false;        private Rect3d _boundRect;        ///<summary>        /// 主命令 DrawShelf        ///</summary>        [CommandMethod("DrawShelf", CommandFlags.Modal)]        publicvoidDrawShelf()        {            _doc = Application.DocumentManager.MdiActiveDocument;            _ed = _doc.Editor;            _db = _doc.Database;            _shelfCount = 1;            _shelfThick = DefaultThickness;            _highlightPoly = null;            _isValidRect = false;            try            {                // 第一步:拾取点(矩形内部点)或者选择线段                PromptPointResult ppr = _ed.GetPoint("\n请点选矩形内部点,或框选4条线段组成的矩形:");                if (ppr.Status != PromptStatus.OK)                {                    CleanHighlight();                    return;                }                _insPoint = ppr.Value;                // 尝试拾取包围这个点的封闭多段线/矩形,或者拾取选择集                PromptSelectionResult psr = _ed.SelectCrossingWindow(                    new Point3d(_insPoint.X - 100, _insPoint.Y - 1000),                    new Point3d(_insPoint.X + 100, _insPoint.Y + 1000));                List<Line> lines = new List<Line>();                Polyline pl = null;                if (psr.Status == PromptStatus.OK)                {                    SelectionSet ss = psr.Value;                    foreach (ObjectId oid in ss.GetObjectIds())                    {                        using (DBObject obj = oid.Open(OpenMode.ForRead))                        {                            if (obj is Line line)                                lines.Add(line);                            else if (obj is Polyline p)                                pl = p;                        }                    }                }                // 解析图形,得到外框矩形                if (pl != null && pl.Closed)                {                    // 找到封闭多段线                    _boundRect = GetRectFromPolyline(pl);                    _isValidRect = CheckValidRect(_boundRect);                }                else if (lines.Count >= 4)                {                    // 4条线段,尝试重构矩形,带闭合阈值容错                    _boundRect = BuildRectFromLines(lines);                    _isValidRect = CheckValidRect(_boundRect);                }                else                {                    _ed.WriteMessage("\n未能识别有效矩形,请重新拾取!");                    CleanHighlight();                    return;                }                if (!_isValidRect)                {                    _ed.WriteMessage("\n识别图形不是有效矩形,请检查图形!");                    CleanHighlight();                    return;                }                // 创建高亮框                CreateHighlightPoly(_boundRect);                // 第二步:交互实时预览,W增加层数 S减少层数 T修改厚度                bool finish = false;                while (!finish)                {                    PromptKeywordOptions pko = new PromptKeywordOptions(                        $"\n【预览】层数:{_shelfCount},厚度:{_shelfThick:F2} | W+层数 S-层数 T设置厚度 回车确认绘制");                    pko.Keywords.Add("W");                    pko.Keywords.Add("S");                    pko.Keywords.Add("T");                    pko.AllowNone = true;                    PromptResult pr = _ed.GetKeywords(pko);                    switch (pr.Status)                    {                        case PromptStatus.OK:                            switch (pr.StringResult)                            {                                case "W":                                    _shelfCount++;                                    UpdatePreview();                                    break;                                case "S":                                    if (_shelfCount > 1)                                    {                                        _shelfCount--;                                        UpdatePreview();                                    }                                    else                                    {                                        _ed.WriteMessage("\n层数不能小于1");                                    }                                    break;                                case "T":                                    PromptDoubleOptions pdo = new PromptDoubleOptions("\n输入层板厚度");                                    pdo.DefaultValue = _shelfThick;                                    PromptDoubleResult pdr = _ed.GetDouble(pdo);                                    if (pdr.Status == PromptStatus.OK && pdr.Value > 0)                                    {                                        _shelfThick = pdr.Value;                                        UpdatePreview();                                    }                                    break;                            }                            break;                        case PromptStatus.None:                            // 回车确认绘制                            finish = true;                            break;                        default:                            finish = true;                            break;                    }                }                // 正式绘制层板                int drawed = DrawShelfGeometry(_boundRect, _shelfCount, _shelfThick);                _ed.WriteMessage($"\n绘制完成!一共生成 {drawed} 块层板");            }            catch (Exception ex)            {                _ed.WriteMessage($"\n插件异常:{ex.Message}");            }            finally            {                CleanHighlight();            }        }        #region 矩形解析        ///<summary>        /// 从封闭多段线获取外接矩形        ///</summary>        private Rect3d GetRectFromPolyline(Polyline pl)        {            Extents3d ext = pl.GeometricExtents;            return new Rect3d(ext.MinPoint, ext.MaxPoint);        }        ///<summary>        /// 从4条线段重构矩形(带闭合阈值容错)        ///</summary>        private Rect3d BuildRectFromLines(List<Line> lines)        {            Point3dCollection pts = new Point3dCollection();            foreach (var ln in lines)            {                pts.Add(ln.StartPoint);                pts.Add(ln.EndPoint);            }            double minX = pts.Cast<Point3d>().Min(p => p.X);            double maxX = pts.Cast<Point3d>().Max(p => p.X);            double minY = pts.Cast<Point3d>().Min(p => p.Y);            double maxY = pts.Cast<Point3d>().Max(p => p.Y);            // 阈值修正,微小缺口自动闭合            if (Math.Abs(maxX - minX) < CloseTolerance || Math.Abs(maxY - minY) < CloseTolerance)                return new Rect3d();            return new Rect3d(new Point3d(minX, minY, 0), new Point3d(maxX, maxY, 0));        }        privateboolCheckValidRect(Rect3d rect)        {            if (rect.Min.IsEqualTo(rect.Max, new Tolerance(CloseTolerance, CloseTolerance)))                return false;            double w = rect.Width;            double h = rect.Height;            if (w < CloseTolerance || h < CloseTolerance)                return false;            return true;        }        #endregion        #region 高亮预览        ///<summary>        /// 创建外框高亮多段线        ///</summary>        privatevoidCreateHighlightPoly(Rect3d rect)        {            CleanHighlight();            _highlightPoly = new Polyline();            _highlightPoly.AddVertexAt(0new Point2d(rect.Min.X, rect.Min.Y), 000);            _highlightPoly.AddVertexAt(1new Point2d(rect.Max.X, rect.Min.Y), 000);            _highlightPoly.AddVertexAt(2new Point2d(rect.Max.X, rect.Max.Y), 000);            _highlightPoly.AddVertexAt(3new Point2d(rect.Min.X, rect.Max.Y), 000);            _highlightPoly.Closed = true;            _highlightPoly.ColorIndex = 1// 红色高亮            _highlightPoly.LineWeight = LineWeight.LineWeight050;            using (Transaction tr = _db.TransactionManager.StartTransaction())            {                BlockTable bt = tr.GetObject(_db.BlockTableId, OpenMode.ForRead) as BlockTable;                BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;                ObjectId id = btr.AppendEntity(_highlightPoly);                tr.AddNewlyCreatedDBObject(_highlightPoly, true);                tr.Commit();            }        }        ///<summary>        /// 更新预览(重绘高亮,实时看层数变化)        ///</summary>        privatevoidUpdatePreview()        {            CleanHighlight();            CreateHighlightPoly(_boundRect);            Application.UpdateScreen();        }        ///<summary>        /// 清除高亮        ///</summary>        privatevoidCleanHighlight()        {            if (_highlightPoly != null && !_highlightPoly.IsDisposed)            {                try                {                    using (Transaction tr = _db.TransactionManager.StartTransaction())                    {                        _highlightPoly.UpgradeOpen();                        _highlightPoly.Erase();                        tr.Commit();                    }                }                catch                {                }                _highlightPoly = null;            }        }        #endregion        #region 绘制层板核心        ///<summary>        /// 在矩形内部居中绘制层板        ///</summary>        privateintDrawShelfGeometry(Rect3d rect, int count, double thick)        {            double boxH = rect.Height;            double boxW = rect.Width;            // 总占用高度 = 层数*厚度            double totalShelfH = count * thick;            // 上下留白均分            double gapTotal = boxH - totalShelfH;            if (gapTotal < 0)            {                _ed.WriteMessage("\n警告:层板总高度大于外框高度!");                gapTotal = 0;            }            double gapEach = gapTotal / (count + 1);            double startY = rect.Min.Y + gapEach + thick / 2;            int drawNum = 0;            using (Transaction tr = _db.TransactionManager.StartTransaction())            {                BlockTable bt = tr.GetObject(_db.BlockTableId, OpenMode.ForRead) as BlockTable;                BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;                for (int i = 0; i < count; i++)                {                    double yPos = startY + i * (thick + gapEach);                    // 绘制层板矩形                    Polyline shelfPl = new Polyline();                    shelfPl.AddVertexAt(0new Point2d(rect.Min.X, yPos - thick / 2), 000);                    shelfPl.AddVertexAt(1new Point2d(rect.Max.X, yPos - thick / 2), 000);                    shelfPl.AddVertexAt(2new Point2d(rect.Max.X, yPos + thick / 2), 000);                    shelfPl.AddVertexAt(3new Point2d(rect.Min.X, yPos + thick / 2), 000);                    shelfPl.Closed = true;                    shelfPl.ColorIndex = 3// 绿色层板                    ObjectId oid = btr.AppendEntity(shelfPl);                    tr.AddNewlyCreatedDBObject(shelfPl, true);                    drawNum++;                }                tr.Commit();            }            return drawNum;        }        #endregion        ///<summary>        /// 矩形辅助结构体        ///</summary>        public struct Rect3d        {            public Point3d Min;            public Point3d Max;            publicRect3d(Point3d min, Point3d max)            {                Min = min;                Max = max;            }            public double Width => Max.X - Min.X;            public double Height => Max.Y - Min.Y;        }    }}

当前代码仅供参考

编译加载

不懂的,翻环境篇/加载篇。这里只写关键步骤。

  1. Visual Studio 新建“类库(.NET Framework)”项目。

  2. 目标框架选 .NET Framework 4.8。

  3. 引用 acdbmgd.dllacmgd.dll

  4. 粘贴代码,编译生成 DLL。

  5. 打开 AutoCAD,输入 NETLOAD

  6. 选择刚生成的 DLL。

  7. 输入命令:DrawShelf

我踩的坑

坑 1:高亮框不消失

AI 第一版给的代码,画完层板之后,红色高亮框还留在图上。

怎么解决:用了 try...finally,不管成功还是异常,最后一定执行 CleanHighlight(),把高亮框删掉。


坑 2:层板数量减到 0

按 S 一直减,减到 0 之后,插件会画出 0 块层板,但预览还在。

怎么解决:加了判断,_shelfCount > 1 才能减,减到 1 就提示“层数不能小于1”。


坑 3:层板总厚度超过柜体高度

如果层数太多、厚度太大,层板会超出柜体。

怎么解决:算 gapTotal 的时候判断,如果小于 0,提示警告,并把留白设为 0。这样层板会紧贴着画,不会跑到柜子外面。


坑 4:用直线画的矩形不识别

新手画图经常用 4 条直线拼矩形,不是闭合多段线。

怎么解决:加了 BuildRectFromLines,把 4 条线的端点全部收集起来,取最大最小值重构矩形。还加了 CloseTolerance 闭合阈值,即使线没完全接上,也能容错。

获取源码和提示词

这篇的完整代码和 AI 提示词,我整理好了。

回复“层板”,直接领取。

上一篇的铰链孔源码,回复“铰链孔”领取。

如果你也是全屋定制设计师、拆单师,想利用下班时间学一门真正能变现的技能,关注我,我按打工人的节奏更新,全程带新手落地。

下一篇预告

下一篇继续实战:

实战|用 AI 写 CAD 插件:一键标注柜体尺寸(附源码+提示词)

我们会让插件自动识别柜体外框,并标注总宽、总高、层板间距。

《零基础 CAD 插件从 0 到 1》系列:

关注我,不错过后续更新。如果这篇对你有帮助,点个,转发给身边的拆单同行。

相关学习资料