一、AutoCAD .NET API 事件机制
- 事件监听核心
- Database.ModifyObjects 事件
当数据库中的实体(如图形对象)发生修改时触发,包括:
-
几何属性变更(移动、缩放、旋转)。
-
非几何属性变更(颜色、线型、图层)。
-
删除或复制操作(需结合事件参数判断)。
-
事件参数 ObjectModifiedEventArgs
-
GetModifiedObjectIds(OpenMode) :获取修改的实体ID列表, OpenMode 控制访问权限(如 ForRead 或 ForWrite )。
-
通过遍历实体ID,获取对应的 Entity 对象进行操作。
二、实体移动检测原理
- 几何包围盒( GeometricExtents )
- 定义:
每个实体( Entity )都有一个 GeometricExtents 属性,表示其在三维空间中的最小包围盒,包含:
-
MinPoint :包围盒最小角点坐标(X,Y,Z)。
-
MaxPoint :包围盒最大角点坐标(X,Y,Z)。
-
中心点计算:
中心点 = (MinPoint + MaxPoint) / 2 ,用于表征实体的位置。
移动判断逻辑:若修改前后中心点坐标差异超过阈值(如 1e-9 ),则认为实体发生移动
核心逻辑流程
- 事件注册:
通过 RegisterIndexEvent 命令绑定 ModifyObjects 事件,开始监听实体修改。
- 移动检测:
-
遍历所有修改的实体,获取新旧版本的包围盒中心点。
-
对比中心点差异,判断是否为移动操作。
- 颜色变更:
-
生成随机 ColorIndex ,排除绿色(3号)和当前颜色索引。
-
直接设置 entity.ColorIndex = newIndex ,触发视觉更新。
- 事件注销:
通过 UnregisterIndexEvent 移除事件监听,释放资源。
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System;
public class ColorIndexChangeDemo
{
private Document doc;
private Database db;
private Editor ed;
private const int GreenColorIndex = 3; // 绿色对应的ColorIndex(3号色为标准绿色)
private readonly Random random = new Random();
CommandMethod("RegisterIndexEvent")
public void RegisterIndexEvent()
{
doc = Application.DocumentManager.MdiActiveDocument;
db = doc.Database;
ed = doc.Editor;
db.ModifyObjects += OnEntityMoved; // 注册移动事件
ed.WriteMessage("\n已启用ColorIndex变色功能(避免3号绿色)");
}
private void OnEntityMoved(object sender, ObjectModifiedEventArgs e)
{
try
{
using (Transaction trans = doc.TransactionManager.StartTransaction())
{
foreach (ObjectId objId in e.GetModifiedObjectIds(OpenMode.ForWrite))
{
Entity entity = trans.GetObject(objId, OpenMode.ForWrite) as Entity;
if (entity == null) continue;
// 检测移动(基于包围盒中心点)
if (IsEntityMoved(entity, trans))
{
ChangeColorByIndex(entity); // 修改ColorIndex
ed.WriteMessage($"\n实体{entity.GetType().Name}颜色已更新为索引{entity.ColorIndex}");
}
}
trans.Commit();
}
}
catch (Exception ex)
{
ed.WriteMessage($"\n错误:{ex.Message}");
}
}
/// <summary>
/// 检测实体移动(包围盒中心点变化)
/// </summary>
private bool IsEntityMoved(Entity entity, Transaction trans)
{
using (DBObject oldObj = trans.GetObject(entity.Id, OpenMode.ForRead, true))
{
if (oldObj is not Entity oldEntity) return false;
return !GetCenter(oldEntity).IsEqualTo(GetCenter(entity), 1e-9);
}
}
/// <summary>
/// 获取包围盒中心点
/// </summary>
private Point3d GetCenter(Entity entity)
{
GeometricExtents extents = entity.GeometricExtents;
return extents.IsValid ?
new Point3d((extents.MinPoint.X + extents.MaxPoint.X)/2,
(extents.MinPoint.Y + extents.MaxPoint.Y)/2,
(extents.MinPoint.Z + extents.MaxPoint.Z)/2) :
Point3d.Origin;
}
/// <summary>
/// 安全修改ColorIndex(避开绿色和当前索引)
/// </summary>
private void ChangeColorByIndex(Entity entity)
{
int currentIndex = entity.ColorIndex; // 获取当前索引
int newIndex;
do
{
// 生成1-255的随机索引(ColorIndex范围:0=随层,1-255为具体颜色)
newIndex = random.Next(1, 256);
} while (newIndex == GreenColorIndex || newIndex == currentIndex); // 排除绿色和当前索引
entity.ColorIndex = newIndex; // 直接设置索引
}
CommandMethod("UnregisterIndexEvent")
public void UnregisterIndexEvent()
{
if (db != null)
{
db.ModifyObjects -= OnEntityMoved;
ed.WriteMessage("\n已停止ColorIndex变色功能");
}
}
}