遇到一个口头机遇的答辩准备7(接1,实现代码整理与解读)
到今天应该没有还没交作业的宝子了吧……有的话也是命了……来看看具体的代码实现吧……因为是小白可能不是很行业常规处理……也欢迎专业宝子指导……我主要准备CAD这题的答辩一、我的项目目录结构 Commands 主要放的是命令入口文件Seed.cs 题目要求的种子填充功能Statistics.cs 题目要求的统计功能 Core Helpers主要是具体实现的部分包括各种工具BoundaryHelper.cs 边界选择是否合法CommandData.cs 全局配置常量设置DataHelper.cs XData管理工具类这个不知道是不是符合行业规矩EntityHelper.cs 主要放实体操作的移动图元、复制图元GeometryHelper.cs 一些计算相关的功能LayerHelper.cs 层相关的功能创建层、复制层、删除层、置顶层RegionConverter.cs 弧线的处理SeedGenerator.cs 种子的处理平铺、裁剪、闭合SeedHelper.cs 种子选择是否合法、自动选择种子 Services主要放的是倒计时的服务IdeCountdownService.cs 计时器二、命令注册题目给了2个命令Seed和Statistics所以我建了2个命令相关的文件嘛其实最早的是都塞一个文件的所以命令不是跟文件有直接关系分别在对应的Seed.cs 、Statistics.cs 这两个文件里。先空的文件简单有个输出可以自测看看对了没using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Runtime; using SeedFill.Core.Helpers; using System; namespace SeedFill { public class SeedFillCommand { [CommandMethod(Seed)] public void SeedFill() { try { Document doc Application.DocumentManager.MdiActiveDocument; Editor ed doc.Editor; Database db doc.Database; // 先略…… ed.WriteMessage(\n✅ Seed 命令启动 - 种子填充工具); } catch (System.Exception ex) { } } } }using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Runtime; using SeedFill.Core.Helpers; using System; namespace SeedFill { public class SeedFillCommand { [CommandMethod(Statistics)] [CommandMethod(STS)] public void ShowStatistics() { try { Document doc Application.DocumentManager.MdiActiveDocument; Editor ed doc.Editor; Database db doc.Database; // 先略…… ed.WriteMessage(\n✅ Statistics、STS 种子填充统计命令); } catch (System.Exception ex) { } } } }可能注意到了后面的命令注册我写了2个这个中括号的看着和Revit的事务申明长着很像吧但是这个是命令注册哦……他算是别名简直是记不住单词宝宝的福音都可以执行命令可以有多个别名而且和方法名叫啥没啥关系不过要求方法必须是public、void、无参数、实例方法。他疏于 AutoCAD .NET API 的命令命名空间using Autodesk.AutoCAD.Runtime;他有这么几个写法[CommandMethod(命令名)] public void 对应执行方法() { }[CommandMethod(命令名)] [CommandMethod(命令别名)] public void 对应执行方法() { }[CommandMethod( 命令名, 命令组名, //不写默认 CommandFlags.标志1 | CommandFlags.标志2 //|连接是且的意思 )] public void 对应执行方法() // 对应执行方法 { }前面2个很好理解实际也用了后面这个来讲讲早知道感觉可以用哦命令名和命令组名没啥歧义也很好理解拿C#比喻的话就是“类名和命名空间差不多吧”主要是下面这个标记哦有这么几种CommandFlags.Modal// 普通命令默认必须等你这个命令跑完CAD 才能干别的。CommandFlags.Session // 跨文档CommandFlags.Redraw// 执行后自动重画执行完自动刷新必加CommandFlags.NoPerspective// 禁止在透视视图用只在 2D 用必加CommandFlags.NoMultiple // 不允许多次嵌套CommandFlags.UsePickSet// 使用当前选择集直接用用户预选对象统计必加【加载运行流程】编译成.dll → CAD输入NETLOAD加载dll → 输入你定义的命令 → CAD自动找到[Command]标记的方法并执行。三、初始化 CAD 上下文固定三套件Document doc Application.DocumentManager.MdiActiveDocument; Editor ed doc.Editor; Database db doc.Database;Document 获取当前文档管理整个dwg文档【常用属性】doc.Editor → 获取编辑器Editordoc.Database → 获取数据库Databasedoc.Name → 文件名doc.Path → 文件路径doc.IsActive → 是否当前激活【常用方法】doc.Save() → 保存doc.Close() → 关闭doc.LockDocument() → 加锁多文档安全Editor 获取当前编辑器命令行屏幕交互和用户交互、命令行、选择、点、提示【常用属性】ed.CurrentUserCoordinateSystem → 当前UCS用户坐标系之前有讲过坐标系哦ed.View → 视图【常用方法】ed.WriteMessage(\nHello Word!);→ 输出Hello WordPromptPointResult ppr ed.GetPoint(\n请指定起点)Point3d pt ppr.Value;→ 获取一个位置点坐标PromptSelectionResult psr ed.GetSelection();SelectionSet sspsr.Value;→ 获取选择集图元集合PromptKeywordOptions pko new PromptKeywordOptions(\n选择[Yes/No]);pko,Keywords.Add(Yes);pko.Keywords.Add(No);PromptResult pr ed.GerKeywords(pko); →获取关键字/选项啊啊啊这个可以用户选选择还是绘制……好吧当时不知道emmm……PromptStringResult psr ed.GetString(\n输入名称);→ 获取字符串PromptIntegerResult pired.GetInteger(\n输入数字);→ 获取整型数字PromptDoubleResult pdr ed.GetDouble(\n输入长度)→ 获取浮点型数字ed.ClearInputBuffer(); →清空输入使用场景命令刚启动是清空、连续多次交互不希望把上一步输入当作下一步默认值的时候啊啊啊这个也有用……之前也不知道……嘤嘤嘤Database 获取当前数据库图纸里多有图元数据增删改查【常用属性】db.BlockTableId→ 块表所有图元都在这里db.LayerTableId→ 图层表db.TextStyleTableId→ 文字样式db.TransactionManager→ 事务管理器增删改查必须【常用方法】Transaction tr db.TransactionManager.StarTransaction();→ 启动事务操作图元必用注意事务不能嵌套BlockTable bt tr.GetObject(db.BlockTableId,OpenMode,ForRead); //块可以理解成清单目录所以用ForRead读的模式除非操作块用读的模式另外OpenMode是Autodesk.AutoCAD.DatabaseServices.OpenMode的枚举enum他有3个常用值OpendMode.ForRead只读、OpenMode.ForWrite可写、OpenMode.NotOpen不打开BlockTableRecord btr tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); //某个具体块/空间他才是真正的“容器画布”所以用.ForWrite 写的模式→ 打开模型空间btr.AppendEntity(line);tr.AddNewlyCreatedDBObject(line,true);→ 添加图元到图纸Line line tr.GetObject(lineId,OpenMpde.ForWrite) as Line;Line,StartPoint new Point3d(0,0,0);→打开图元读/改四、获取边界首先是本来题目的要求必须是闭合的多线段其次他要在边界的层上。至于那个大小没太明白含义可能性能或者怕答题者直接硬拼题目的多边形……不清楚了。之后就还有我自己不太点的准于是就想着点的不对要提示之后可以继续点所以做了循环但是要是不想做了一直死循环也不好于是做了esc退出// 引用CAD数据库服务用于事务、图元、图层、ObjectId等操作 using Autodesk.AutoCAD.DatabaseServices; // 引用CAD编辑器服务用于用户选择对象、交互提示、命令行输出 using Autodesk.AutoCAD.EditorInput; // 核心帮助类命名空间 namespace SeedFill.Core.Helpers { /// summary /// 边界选择帮助类 /// 功能提供闭合边界的选择、校验、图层设置、面积计算等一体化处理 /// /summary public static class BoundaryHelper { #region 选择闭合边界 /// summary /// 供外部调用的闭合边界选择方法 /// 核心功能 /// 1. 限制用户只能选择【闭合多段线】 /// 2. 自动校验选择对象的有效性 /// 3. 自动将边界移动到指定图层并修改颜色 /// 4. 输出边界面积 /// /summary /// param namedbCAD数据库对象/param /// param nameedCAD编辑器对象/param /// returns选中的有效闭合多段线的ObjectId取消则返回Null/returns public static ObjectId SelectClosedBoundary(Database db, Editor ed) { // 循环选择直到用户选中有效边界 或 按下ESC取消 while (true) { // // 1. 创建选择图元的配置选项 // 提示用户选择边界多段线 // PromptEntityOptions opt new PromptEntityOptions(\n请选择边界多段线); // 设置选择错误时的提示信息 opt.SetRejectMessage(\n❌ 只能选择闭合多段线); // 限制用户只能选择 Polyline多段线类型的图元 opt.AddAllowedClass(typeof(Polyline), true); // // 2. 调用编辑器让用户在CAD界面选择对象 // 返回选择结果包含状态、选中对象ID等 // PromptEntityResult res ed.GetEntity(opt); // // 3. 判断用户是否按下 ESC 取消选择 // 是输出提示返回空ID退出方法 // if (res.Status PromptStatus.Cancel) { ed.WriteMessage(\n已取消选择); return ObjectId.Null; } // // 4. 开启CAD事务必须所有数据库操作都需要事务 // using 自动释放事务资源避免内存泄漏 // using (Transaction tr db.TransactionManager.StartTransaction()) { // 根据选中的ID从事务中读取多段线对象只读模式 Polyline pline tr.GetObject(res.ObjectId, OpenMode.ForRead) as Polyline; // // 5. 双重校验图元不为空 多段线是闭合状态 // 满足条件 有效边界 // if (pline ! null pline.Closed) { // 命令行输出选择成功提示 ed.WriteMessage(\n✅ 边界选择成功); // 输出边界面积保留4位小数提升可读性 ed.WriteMessage($\n 边界面积{pline.Area:F4}); // // 6. 把选中的边界挪到边界层 // 自动创建图层 → 将边界移动到指定图层 → 设置颜色 // 图层名和颜色从配置类 CommandData 中读取 // EntityHelper.MoveEntityToLayer(db,tr, res.ObjectId, CommandData.BOUNDARY_LAYER, CommandData.BOUNDARY_COLOR); // 提交事务保存图层修改等数据库操作 tr.Commit(); // 返回有效边界的ID供后续填充功能使用 return res.ObjectId; } } // using 结束 → 事务自动销毁未提交则自动回滚 // // 7. 选择无效用户选了非闭合多段线 // 输出错误提示循环继续让用户重新选择 // ed.WriteMessage(\n❌ 错误必须选择闭合多段线); } } #endregion } }这里要注意了错误提示要先写不然会报错哦~~~之后就是在Seed.cs里面调用它ObjectId boundaryId BoundaryHelper.SelectClosedBoundary(db, ed); if (boundaryId.IsNull) return;五、获取种子之后是选择种子矩形本来就多个直角判断多一个在不在范围内结果需求上有写等一段时间绘制啥的。感觉交互有点描述的冲突可能是考官想到不同难度任选吧哎早点知道PromptKeywordOptions就可以用户选下2个都做了…… #region 描述 …… #endregion 代码块是c#的好东西个人觉得【手动选择种子】#region 手动选择种子原有逻辑完整保留 /// summary /// 手动模式让用户选择一个【有效种子矩形】 /// 有效条件 /// 1. 必须是标准矩形多段线 /// 2. 必须完全在边界内部 /// 3. 自动放入种子图层 /// /summary /// param namedb数据库/param /// param nameed编辑器/param /// param nameboundaryId边界ID/param /// returns有效种子ID取消返回Null/returns public static ObjectId SelectValidSeedManually(Database db, Editor ed, ObjectId boundaryId) { // 参数空校验 if (db null || ed null || boundaryId.IsNull) return ObjectId.Null; // 循环选择直到选中有效种子 或 ESC取消 while (true) { // 创建选择配置仅允许选择多段线 PromptEntityOptions opt new PromptEntityOptions(\n请选择种子矩形); opt.SetRejectMessage(\n必须是矩形且在边界内); opt.AddAllowedClass(typeof(Polyline), true); // 让用户在CAD中选择对象 PromptEntityResult res ed.GetEntity(opt); // ESC取消 → 返回空 if (res.Status PromptStatus.Cancel) { ed.WriteMessage(\n已取消选择); return ObjectId.Null; } // 开启事务校验选中对象 using (Transaction tr db.TransactionManager.StartTransaction()) { // 打开种子和边界 Polyline boundary tr.GetObject(boundaryId, OpenMode.ForRead) as Polyline; Polyline seed tr.GetObject(res.ObjectId, OpenMode.ForRead) as Polyline; // 三重校验非空 标准矩形 完全在边界内 if (res ! null boundary ! null IsStandardRectangle(seed) GeometryHelper.IsSeedFullyInside(boundary, seed)) { // 校验通过移动到种子图层并设置颜色 EntityHelper.MoveEntityToLayer(db,tr, res.ObjectId, CommandData.SEED_LAYER, CommandData.SEED_COLOR); tr.Commit(); ed.WriteMessage(\n✅ 种子选择成功); return res.ObjectId; } } // 选择无效提示重新选择 ed.WriteMessage(\n❌ 不是合法矩形种子请重新选择); } } #endregionemmmm……今天就先写到这里……明天继续……