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 方法可以定义实体上的对象捕捉点(如端点、中点、圆心等)。
相关推荐
z落落2 小时前
C# WinForm 线程池与事件等待+进度条暂停恢复实战案例
开发语言·c#
酷酷的身影4 小时前
Managers/APConfigManager.cs
开发语言·ui·c#
贾斯汀frank16 小时前
C# 15 类型系统改进:Union Types
开发语言·windows·c#
时代的狂18 小时前
如何理解 C# 的 async 和 await
c#·.netcore·async·await
xiaoshuaishuai821 小时前
C# AI实现PR处理、单元测试
开发语言·c#·log4j
LONGZHIQIN21 小时前
C#基础复习笔记
开发语言·笔记·c#
时代的狂1 天前
如何理解 C#/.NET 的依赖注入与生命周期
c#·.net·依赖注入·控制反转
品尚公益团队1 天前
C#在asp.net网页开发中的带cookie登录实现
前端·c#·asp.net
吴可可1231 天前
C#自定义CAD多段线零件实体
c#