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

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

核心步骤与代码示例

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

    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创建实体的副本。(通常调用基类方法)

    关键方法实现示例:

    {
        // ... 属性与构造函数同上 ...
    
        // 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 中注册,然后才能添加到数据库。

    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 方法可以定义实体上的对象捕捉点(如端点、中点、圆心等)。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值