news 2026/3/13 5:07:46

6.基于C#的CAD二次开发-实体操作实战(Entity对象属性与方法的深度应用)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
6.基于C#的CAD二次开发-实体操作实战(Entity对象属性与方法的深度应用)

1. Entity对象基础操作入门

在CAD二次开发中,Entity对象是所有图形实体的基类,理解它的基本操作是开发的基础。我们先从最简单的实体创建和属性修改开始。

创建直线实体的完整示例代码如下:

using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; public void CreateLine() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { // 获取模型空间块表记录 BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject( bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); // 创建直线对象 Line line = new Line( new Point3d(0, 0, 0), new Point3d(100, 100, 0)); // 设置线型属性 line.ColorIndex = 1; // 红色 line.LineWeight = LineWeight.LineWeight030; // 添加到模型空间 btr.AppendEntity(line); tr.AddNewlyCreatedDBObject(line, true); tr.Commit(); } }

这段代码展示了Entity对象的基本生命周期:创建→设置属性→添加到数据库→提交事务。实际开发中我经常遇到新手忘记提交事务导致操作不生效的情况,这点需要特别注意。

2. 几何变换实战技巧

几何变换是CAD开发中最常用的功能之一,Entity对象提供了多种变换方法:

2.1 平移变换

public void MoveEntity(ObjectId entId, Vector3d offset) { using (Transaction tr = entId.Database.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForWrite); ent.TransformBy(Matrix3d.Displacement(offset)); tr.Commit(); } }

2.2 旋转变换

public void RotateEntity(ObjectId entId, Point3d basePoint, double angle) { using (Transaction tr = entId.Database.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForWrite); ent.TransformBy(Matrix3d.Rotation( angle, Vector3d.ZAxis, basePoint)); tr.Commit(); } }

2.3 缩放变换

public void ScaleEntity(ObjectId entId, Point3d basePoint, double scaleFactor) { using (Transaction tr = entId.Database.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForWrite); ent.TransformBy(Matrix3d.Scaling(scaleFactor, basePoint)); tr.Commit(); } }

在实际项目中,我经常需要组合这些变换。比如先旋转再平移,这时候要注意变换矩阵的乘法顺序会影响最终结果。正确的做法是:

Matrix3d mat = Matrix3d.Rotation(angle, Vector3d.ZAxis, center) * Matrix3d.Displacement(offset); ent.TransformBy(mat);

3. 批量处理实战

批量处理能显著提高操作效率,以下是几种常见场景的实现:

3.1 批量修改图层

public void ChangeLayer(ObjectIdCollection ids, string layerName) { if (ids.Count == 0) return; Database db = ids[0].Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { // 验证图层是否存在 LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead); if (!lt.Has(layerName)) { tr.Abort(); throw new Exception($"图层{layerName}不存在"); } // 批量修改 foreach (ObjectId id in ids) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); ent.Layer = layerName; } tr.Commit(); } }

3.2 批量删除实体

public void DeleteEntities(ObjectIdCollection ids) { if (ids.Count == 0) return; Database db = ids[0].Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { foreach (ObjectId id in ids) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); ent.Erase(); } tr.Commit(); } }

在批量处理时,我建议先对ObjectIdCollection进行非空检查,避免无效操作。同时要注意事务的范围,不要把整个循环放在事务外,这样会导致性能下降。

4. 高级交互操作

4.1 使用Jig实现动态绘制

EntityJig可以实现实时的交互式绘图效果,下面是绘制多边形的实现:

public class PolyJig : EntityJig { private Polyline pline; private Point3d currentPoint; private int vertexCount = 0; public PolyJig() : base(new Polyline()) { pline = (Polyline)Entity; pline.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0); vertexCount++; } protected override SamplerStatus Sampler(JigPrompts prompts) { JigPromptPointOptions opts = new JigPromptPointOptions("\n指定下一点: "); opts.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.NoZeroResponseAccepted | UserInputControls.NoNegativeResponseAccepted; PromptPointResult res = prompts.AcquirePoint(opts); if (res.Status == PromptStatus.Cancel) return SamplerStatus.Cancel; if (res.Value == currentPoint) return SamplerStatus.NoChange; currentPoint = res.Value; return SamplerStatus.OK; } protected override bool Update() { pline.AddVertexAt(vertexCount, new Point2d(currentPoint.X, currentPoint.Y), 0, 0, 0); vertexCount++; return true; } public Entity GetEntity() { return pline; } }

使用时只需要创建Jig实例并启动拖拽操作:

Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PolyJig jig = new PolyJig(); PromptResult res = ed.Drag(jig); if (res.Status == PromptStatus.OK) { // 添加到数据库 Database db = HostApplicationServices.WorkingDatabase; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject( bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); btr.AppendEntity(jig.GetEntity()); tr.AddNewlyCreatedDBObject(jig.GetEntity(), true); tr.Commit(); } }

4.2 实体捕捉与修改

实现夹点编辑功能:

public void EditWithGrips(ObjectId entId) { Database db = entId.Database; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForWrite); // 获取实体夹点 Point3dCollection grips = new Point3dCollection(); IntegerCollection snapModes = new IntegerCollection(); IntegerCollection geomIds = new IntegerCollection(); ent.GetGripPoints(grips, snapModes, geomIds); // 让用户选择夹点 PromptIntegerResult res = ed.GetInteger("\n选择要移动的夹点(1-"+grips.Count+"):"); if (res.Status != PromptStatus.OK) return; int index = res.Value - 1; if (index < 0 || index >= grips.Count) { ed.WriteMessage("\n无效的夹点索引"); return; } // 获取移动向量 PromptPointOptions opts = new PromptPointOptions("\n指定新位置:") .UseBasePoint(grips[index]); opts.UserInputControls = UserInputControls.NoZeroResponseAccepted | UserInputControls.NoNegativeResponseAccepted; PromptPointResult ptRes = ed.GetPoint(opts); if (ptRes.Status != PromptStatus.OK) return; // 移动夹点 Vector3d offset = ptRes.Value - grips[index]; IntegerCollection indices = new IntegerCollection(); indices.Add(index); ent.MoveGripPointsAt(indices, offset); tr.Commit(); } }

5. 性能优化技巧

在处理大量实体时,性能优化尤为重要:

5.1 使用OpenMode.ForRead

只读访问时使用ForRead模式:

using (Transaction tr = db.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForRead); Extents3d extents = ent.GeometricExtents; // 只读操作 // 不需要tr.Commit() }

5.2 批量操作时重用事务

public void ProcessEntities(ObjectIdCollection ids) { if (ids.Count == 0) return; Database db = ids[0].Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { foreach (ObjectId id in ids) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); // 处理逻辑... } tr.Commit(); } }

5.3 使用索引加速查询

public ObjectIdCollection FindEntitiesInArea(Extents3d area) { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; // 创建选择过滤器 TypedValue[] values = new TypedValue[] { new TypedValue((int)DxfCode.Start, "LINE,ARC,CIRCLE") // 只选择这些类型 }; SelectionFilter filter = new SelectionFilter(values); // 使用窗口选择 PromptSelectionResult res = ed.SelectCrossingWindow( area.MinPoint, area.MaxPoint, filter); if (res.Status == PromptStatus.OK) return new ObjectIdCollection(res.Value.GetObjectIds()); else return new ObjectIdCollection(); }

6. 常见问题解决方案

6.1 实体无法修改

常见原因是事务未提交或打开模式不正确:

using (Transaction tr = db.TransactionManager.StartTransaction()) { // 错误:使用ForRead模式尝试修改 // Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForRead); // 正确:使用ForWrite模式 Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForWrite); ent.ColorIndex = 1; tr.Commit(); // 必须提交 }

6.2 实体克隆问题

克隆实体时要注意处理扩展数据:

public Entity CloneEntity(ObjectId entId, Database targetDb) { using (Transaction tr = entId.Database.TransactionManager.StartTransaction()) { Entity source = (Entity)tr.GetObject(entId, OpenMode.ForRead); // 简单克隆(不包含扩展数据) Entity clone = (Entity)source.Clone(); // 如果需要完整克隆(包含扩展数据) IdMapping mapping = new IdMapping(); DBObjectCollection clones = new DBObjectCollection(); source.DeepClone(source.Database, clones, mapping); if (clones.Count > 0) { clone = (Entity)clones[0]; } return clone; } }

6.3 处理复杂实体

对于多段线等复杂实体,需要特殊处理顶点:

public void ProcessPolyline(ObjectId plineId) { using (Transaction tr = plineId.Database.TransactionManager.StartTransaction()) { Polyline pline = (Polyline)tr.GetObject(plineId, OpenMode.ForWrite); // 遍历所有顶点 for (int i = 0; i < pline.NumberOfVertices; i++) { Point2d pt = pline.GetPoint2dAt(i); // 处理顶点... } // 添加新顶点 pline.AddVertexAt(pline.NumberOfVertices, new Point2d(100, 100), 0, 0, 0); tr.Commit(); } }

7. 实战案例:批量偏移曲线

结合前面介绍的技术,我们实现一个实用的批量偏移功能:

public void OffsetCurves(ObjectIdCollection curveIds, double offsetDist) { if (curveIds.Count == 0) return; Database db = curveIds[0].Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject( bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); foreach (ObjectId id in curveIds) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead); if (ent is Curve curve) { try { // 创建偏移曲线 DBObjectCollection offsetCurves = curve.GetOffsetCurves(offsetDist); // 添加到模型空间 foreach (DBObject obj in offsetCurves) { Entity offsetEnt = (Entity)obj; btr.AppendEntity(offsetEnt); tr.AddNewlyCreatedDBObject(offsetEnt, true); } } catch (Autodesk.AutoCAD.Runtime.Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage( $"\n无法偏移实体 {id}: {ex.Message}"); } } } tr.Commit(); } }

这个例子展示了如何:

  1. 处理多种曲线类型(直线、圆弧、多段线等)
  2. 进行批量操作
  3. 添加错误处理
  4. 维护事务完整性

8. 扩展应用:自定义实体操作

除了内置实体类型,我们还可以操作自定义实体:

public void ProcessCustomEntity(ObjectId entId) { using (Transaction tr = entId.Database.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForRead); // 检查是否为自定义实体 if (ent is ProxyEntity proxy) { // 获取代理实体的原始类名 string originalClass = proxy.OriginalClassName; // 处理代理实体... } else if (ent.XData != null) { // 处理带有扩展数据的实体 foreach (TypedValue tv in ent.XData) { // 解析扩展数据... } } tr.Commit(); } }

9. 最佳实践总结

经过多个项目的实践,我总结了以下Entity对象操作的最佳实践:

  1. 事务管理

    • 每个独立操作使用单独事务
    • 批量操作合并到一个事务中
    • 及时释放事务资源
  2. 错误处理

    • 捕获特定异常(如eInvalidInput)
    • 提供有意义的错误信息
    • 确保事务在异常时正确回滚
  3. 性能优化

    • 最小化事务范围
    • 合理使用OpenMode
    • 避免频繁的数据库查询
  4. 代码组织

    • 封装常用操作为独立方法
    • 使用扩展方法增强可读性
    • 保持代码与CAD版本兼容

下面是一个封装好的实用工具方法示例:

public static class EntityExtensions { public static void SafeTransform(this Entity ent, Matrix3d mat) { try { ent.TransformBy(mat); } catch (Autodesk.AutoCAD.Runtime.Exception ex) { if (ex.ErrorStatus == ErrorStatus.InvalidGeometry) { // 处理无效几何体情况 } throw; } } public static bool IsVisible(this Entity ent) { return ent.Visible && !ent.IsErased && ent.LayerId.IsValid && ent.ColorIndex != 0; // 0表示BYBLOCK } }

使用时只需要:

ent.SafeTransform(transformationMatrix); if (ent.IsVisible()) { /*...*/ }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/4 1:02:54

Qwen2.5-VL-7B-Instruct开源大模型实操:本地化部署降本增效完整方案

Qwen2.5-VL-7B-Instruct开源大模型实操&#xff1a;本地化部署降本增效完整方案 1. 为什么你需要一个真正“能看懂图”的本地多模态助手 你有没有遇到过这些场景&#xff1a; 截了一张网页&#xff0c;想快速生成对应的HTML代码&#xff0c;却要反复截图、复制、粘贴到不同工…

作者头像 李华
网站建设 2026/3/11 17:43:38

人脸识别OOD模型实测:如何有效拒识低质量样本?

人脸识别OOD模型实测&#xff1a;如何有效拒识低质量样本&#xff1f; 在实际部署人脸识别系统时&#xff0c;你是否遇到过这些情况&#xff1f; 员工打卡时因逆光导致人脸模糊&#xff0c;系统却仍给出0.42的相似度&#xff0c;误判为“同一人”&#xff1b;安防摄像头拍到侧…

作者头像 李华
网站建设 2026/3/12 23:24:32

FPGA加速Hunyuan-MT 7B推理性能优化方案

FPGA加速Hunyuan-MT 7B推理性能优化方案 1. 引言&#xff1a;当翻译大模型遇上FPGA 在机器翻译领域&#xff0c;Hunyuan-MT 7B以其轻量级架构和卓越性能成为业界焦点。这个仅70亿参数的模型在国际翻译比赛中斩获30个语种第一&#xff0c;支持33种语言互译&#xff0c;但如何在…

作者头像 李华
网站建设 2026/3/12 0:51:24

突破限制:3个核心步骤实现Windows远程桌面多用户高效配置

突破限制&#xff1a;3个核心步骤实现Windows远程桌面多用户高效配置 【免费下载链接】rdpwrap RDP Wrapper Library 项目地址: https://gitcode.com/gh_mirrors/rd/rdpwrap &#x1f680; 功能价值&#xff1a;为什么需要RDP Wrapper&#xff1f; 在现代办公中&#x…

作者头像 李华
网站建设 2026/3/12 13:57:37

Nano-Banana Studio效果展示:运动鞋全拆解图+材质标注一体化输出

Nano-Banana Studio效果展示&#xff1a;运动鞋全拆解图材质标注一体化输出 1. 这不是PPT&#xff0c;是会“解剖”运动鞋的AI 你有没有见过一双运动鞋被完整摊开的样子&#xff1f;不是剪开实物&#xff0c;而是让整双鞋像工程师手稿一样——鞋带、中底、外底、织物鞋面、TP…

作者头像 李华