C# CAD二次开发自定义实体实现

在 C#中进行 AutoCAD .NET API 二次开发时,继承 Entity 类并重写其关键方法是创建自定义实体的核心。Entity 类是 AutoCAD 中所有图形对象(如直线、圆、多段线)的基类,位于 Autodesk.AutoCAD.DatabaseServices 命名空间。

核心步骤与代码示例

  1. 创建自定义实体类

    创建一个新的类,继承自 Autodesk.AutoCAD.DatabaseServices.Entity。必须使用 [CustomObject] 特性进行装饰,以便 AutoCAD 能够识别和注册该自定义对象。

    csharp 复制代码
    using Autodesk.AutoCAD.DatabaseServices;
    using Autodesk.AutoCAD.Geometry;
    using Autodesk.AutoCAD.Runtime;
    
    [CustomObject]
    public class MyCustomEntity : Entity {
        // 自定义属性:例如圆心和半径
        private Point3d _center;
        private double _radius;
    
        public Point3d Center {
            get { return _center; }
            set { _center = value; }
        }
    
        public double Radius {
            get { return _radius; }
            set { _radius = value; }
        }
    
        // 默认构造函数(序列化必需)
        public MyCustomEntity()
        {
            _center = Point3d.Origin;
            _radius = 1.0;
        }
    
        // 带参数的构造函数 public MyCustomEntity(Point3d center, double radius)
        {
            _center = center;
            _radius = radius;
        }
    }
  2. 重写关键方法

    为了确保自定义实体能被正确绘制、选择、夹点编辑和序列化,必须重写以下核心虚方法:

    方法名 作用 是否必须重写
    WorldDraw 在模型空间或图纸空间进行图形绘制。
    ViewportDraw 在特定视口中进行图形绘制(通常可委托给 WorldDraw)。 通常委托
    GetGripPoints 返回实体的夹点位置,用于夹点编辑。 推荐
    MoveGripPointsAt 处理夹点移动时的实体变形逻辑。 推荐
    GetGeomExtents 返回实体的几何边界(用于显示范围、缩放等)。
    TransformBy 对实体应用几何变换(如移动、旋转、缩放)。
    GetStretchPoints 返回可用于拉伸操作的基点。 可选
    MoveStretchPointsAt 处理拉伸点移动时的逻辑。 可选
    IntersectWith 计算与其他实体的交点(用于修剪、延伸等)。 强烈推荐
    Clone 创建实体的副本。 (通常调用基类方法)

    关键方法实现示例:

    csharp 复制代码
    {
        // ... 属性与构造函数同上 ...
    
        // 1. 重写 WorldDraw 方法:定义实体在图形中的外观 public override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw wd)
        {
            if (wd == null) return false;
    
            // 使用 WorldDraw 的 Geometry 对象进行绘制
            // 例如,绘制一个圆(这里用多段线模拟一个圆)
            if (_radius > 0)
            {
                // 创建表示圆的多段线(实际开发中可能使用更底层的图形原语)
                using (Polyline pl = new Polyline())
                {
                    pl.AddVertexAt(0, new Point2d(_center.X - _radius, _center.Y), 0, 0, 0);
                    pl.AddVertexAt(1, new Point2d(_center.X, _center.Y + _radius), 0, 0, 0);
                    pl.AddVertexAt(2, new Point2d(_center.X + _radius, _center.Y), 0, 0, 0);
                    pl.AddVertexAt(3, new Point2d(_center.X, _center.Y - _radius), 0, 0, 0);
                    pl.Closed = true;
                    // 将多段线的几何数据提交给 WorldDraw 进行渲染 wd.Geometry.Draw(pl);
                }

// 也可以绘制圆心标记

wd.Geometry.Circle(_center, Vector3d.ZAxis, _radius);

}

return true;

}

复制代码
    // 2. 重写 GetGeomExtents 方法:返回实体的包围盒
    public override Extents3d GetGeomExtents()
    {
        // 根据圆心和半径计算圆的边界
        return new Extents3d(
            new Point3d(_center.X - _radius, _center.Y - _radius, _center.Z),
            new Point3d(_center.X + _radius, _center.Y + _radius, _center.Z)
        );
    }

    // 3. 重写 TransformBy 方法:实现对实体的移动、旋转、缩放 public override void TransformBy(Matrix3d transform)
    {
        // 变换圆心点 _center = _center.TransformBy(transform);
        // 对于缩放,需要同时处理半径。这里假设变换是均匀缩放。
        // 注意:这是一个简化处理,复杂变换(如非均匀缩放)需要更精细的计算。
        Vector3d xAxis = transform.CoordinateSystem3d.Xaxis;
        double scale = xAxis.Length; // 获取X方向的缩放因子 _radius *= scale;
    }

    // 4. 重写 GetGripPoints 方法:定义夹点位置
    public override void GetGripPoints(
        Point3dCollection gripPoints,
        IntegerCollection osnapModes,
        IntegerCollection geomIds)
    {
        base.GetGripPoints(gripPoints, osnapModes, geomIds); // 可调用基类获取默认夹点
        // 添加圆心和四个象限点作为夹点 gripPoints.Add(_center); // 圆心
        gripPoints.Add(new Point3d(_center.X + _radius, _center.Y, _center.Z)); // 右 gripPoints.Add(new Point3d(_center.X, _center.Y + _radius, _center.Z)); // 上
        gripPoints.Add(new Point3d(_center.X - _radius, _center.Y, _center.Z)); // 左 gripPoints.Add(new Point3d(_center.X, _center.Y - _radius, _center.Z)); // 下
    }

    // 5. 重写 MoveGripPointsAt 方法:响应夹点拖动 public override void MoveGripPointsAt(
        IntegerCollection indices,
        Vector3d offset)
    {
        // indices是被拖动的夹点索引,offset 是移动向量
        foreach (int index in indices)
        {
            if (index == 0) // 拖动圆心夹点
            {
                _center += offset;
            }
            else if (index >= 1 && index <= 4) // 拖动象限点夹点,改变半径 {
                // 简化逻辑:计算新点到圆心的距离作为新半径
                Point3d draggedPoint = GetGripPointByIndex(index) + offset;
                _radius = _center.DistanceTo(draggedPoint);
            }
        }
    }
    // 辅助方法:根据索引获取夹点原始位置
    private Point3d GetGripPointByIndex(int index)
    {
        switch (index)
        {
            case 0: return _center;
            case 1: return new Point3d(_center.X + _radius, _center.Y, _center.Z);
            case 2: return new Point3d(_center.X, _center.Y + _radius, _center.Z);
            case 3: return new Point3d(_center.X - _radius, _center.Y, _center.Z);
            case 4: return new Point3d(_center.X, _center.Y - _radius, _center.Z);
            default: return _center;
        }
    }

    // 6. 重写 Clone 方法:创建实体副本
    public override DBObject Clone()
    {
        // 创建新实例并复制属性            MyCustomEntity cloned = new MyCustomEntity(_center, _radius);
        // 复制从 Entity 基类继承的属性(如图层、颜色、线型等)
        cloned.SetPropertiesFrom(this);
        return cloned;
    }
}
```
  1. 注册与使用自定义实体

    创建实体后,需要通过 RXClass 在 AutoCAD 中注册,然后才能添加到数据库。

    csharp 复制代码
    using Autodesk.AutoCAD.EditorInput;
    using Autodesk.AutoCAD.Runtime;
    
    public class MyCommands {
        [CommandMethod("ADDMYCUSTOM")]
        public void AddMyCustomEntity()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
    
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                // 1. 获取当前空间块表记录(模型空间或图纸空间)
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
    
                // 2. 创建自定义实体实例
                MyCustomEntity myEnt = new MyCustomEntity(new Point3d(0, 0, 0), 5.0);
                myEnt.ColorIndex = 1; // 设置为红色 // 3. 将实体添加到块表记录并通知事务
                btr.AppendEntity(myEnt);
                tr.AddNewlyCreatedDBObject(myEnt, true);
    
                // 4. 提交事务
                tr.Commit();
            }
        }
    }

关键注意事项

  • 序列化支持 :自定义实体类必须有一个无参数的公共构造函数,以便 AutoCAD 在读取 DWG 文件时能够反序列化(重建)该对象。
  • 性能考量WorldDrawIntersectWith 等方法在交互操作中会被频繁调用,其实现应尽可能高效。
  • 复杂几何 :对于复杂形状,WorldDraw 中可能需要使用 Autodesk.AutoCAD.GraphicsInterface 命名空间下的底层图形接口(如 WorldGeometry)进行绘制,而非创建临时 Entity
  • 自定义数据 :除了几何图形,还可以重写 GetXDataSetXData 方法来存储和读取扩展数据。
  • 对象捕捉 :重写 GetOsnapPoints 方法可以定义实体上的对象捕捉点(如端点、中点、圆心等)。
相关推荐
淡海水3 小时前
10-05-高级-模式匹配-CSharp如何改变与数据结构的交互方式
数据结构·算法·c#·模式匹配
XiaoZhenHua983 小时前
C# WinForms + 西门子S7 + SQLite + EPPlus生产数据采集系统架构设计
系统架构·sqlite·c#
Lost of 程序猿4 小时前
船岸数据同步链路实战:SendFlag、单调版本号与断网三天后的续传
后端·c#·asp.net
cjp5601 天前
012.UG二次开发,UG管道服务器与WPF管道通讯,传输JSON数据
c#
jiushidt1 天前
ArcGIS Pro Add‑in 打包流程详解
arcgis·c#·.net·arcgispro
geovindu2 天前
CSharp: Observer Pattern
开发语言·后端·观察者模式·设计模式·c#·.netcore·行为模式
软件黑马王子2 天前
20.Resources资源加载:基本实现
开发语言·前端框架·c#
张人玉2 天前
基于 C# / .NET 8 + Windows Forms + SQLite 的桌面银行业务演示系统——华夏示范银行管理系统
windows·sqlite·c#·.net
1314lay_10072 天前
C#调用Sql Server存储过程,并且使用传入表结构
数据库·经验分享·笔记·sqlserver·c#
慧都小妮子2 天前
.NET 报表控件选型对比:Stimulsoft 与 FastReport 怎么选
c#·.net·报表开发·数据可视化·报表控件·报表引擎选型