在 C# 中进行 AutoCAD 二次开发,实现点击多段线并在点击处打断 2 毫米的功能,核心步骤是:获取点击点、计算打断点、执行打断操作。
核心实现步骤与代码
- 定义命令与获取实体
首先,需要定义一个 AutoCAD 命令,并让用户选择一条多段线。
csharp
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
[CommandMethod("BreakPolyline2mm")]
public void BreakPolyline2mm()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// 1. 选择一条多段线
PromptEntityOptions peo = new PromptEntityOptions("
请选择一条多段线: ");
peo.SetRejectMessage("
请选择一条多段线。");
peo.AddAllowedClass(typeof(Polyline), true);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK) return;
// 2. 获取用户点击的点(在WCS坐标系下)
Point3d pickedPoint = per.PickedPoint;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 打开选中的多段线 Polyline pline = tr.GetObject(per.ObjectId, OpenMode.ForWrite) as Polyline;
if (pline == null) return;
// 3. 将点击点转换到多段线的模型空间(OCS)
Point3d clickedPointOcs = pickedPoint.TransformBy(ed.CurrentUserCoordinateSystem.Inverse());
// 4. 找到点击点所在的多段线线段及参数
double paramAtPoint = pline.GetParameterAtPoint(clickedPointOcs);
int segmentIndex = (int)Math.Floor(paramAtPoint); // 线段索引(从0开始)
// 5. 计算距离点击点前后各1毫米(共2毫米)的两个打断点 // 获取线段起点和终点的参数 double startParam = segmentIndex;
double endParam = segmentIndex + 1;
// 计算线段在参数方向上的单位向量(用于偏移)
Point3d startPoint = pline.GetPointAtParameter(startParam);
Point3d endPoint = pline.GetPointAtParameter(endParam);
Vector3d segmentDirection = (endPoint - startPoint).GetNormal();
// 计算距离(假设绘图单位为毫米)
double offsetDistance = 1.0; // 1毫米
Point3d breakPoint1 = clickedPointOcs segmentDirection * offsetDistance;
Point3d breakPoint2 = clickedPointOcs + segmentDirection * offsetDistance;
// 6. 确保打断点在线段范围内(避免超出边界)
// 计算两个打断点相对于线段起点的参数
double param1 = pline.GetParameterAtPoint(breakPoint1);
double param2 = pline.GetParameterAtPoint(breakPoint2);
// 对参数进行排序,确保 param1 < param2 if (param1 > param2)
{
(param1, param2) = (param2, param1);
(breakPoint1, breakPoint2) = (breakPoint2, breakPoint1);
}
// 7. 执行打断操作
// 使用 BreakAtPoints 方法在两点处打断多段线 DBObjectCollection brokenSegments = pline.GetSplitCurves(new DoubleCollection { param1, param2 });
if (brokenSegments.Count > 0)
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
// 删除原多段线 pline.Erase();
// 添加打断后生成的新对象(可能是多段线或直线段)
foreach (DBObject obj in brokenSegments)
{
Entity newEntity = obj as Entity;
if (newEntity != null)
{
btr.AppendEntity(newEntity);
tr.AddNewlyCreatedDBObject(newEntity, true);
}
}
}
tr.Commit();
}
ed.WriteMessage("
多段线已在点击处成功打断2毫米。");
}
```
2. **关键逻辑说明**
* **参数计算**:`GetParameterAtPoint` 方法用于获取点击点沿多段线的曲线参数,这对于精确定位至关重要。
* **打断点计算**:通过获取点击点所在线段的单位方向向量,向两侧各偏移 1 毫米,计算出两个打断点。
* **边界处理**:通过 `GetParameterAtPoint` 对计算出的打断点进行反向验证,确保其在线段范围内,并通过排序保证参数顺序正确。
* **执行打断**:`GetSplitCurves` 方法是核心,它接受一个参数集合,并在这些参数点处将曲线(多段线)分割。返回的集合包含分割后的新曲线对象。
### 注意事项与优化建议
| 事项 | 说明与建议 |
| :--- | :--- |
| **绘图单位** | 上述代码假设 1 个 AutoCAD 绘图单位代表 1 毫米。如果您的绘图单位是米、英寸等,需要调整 `offsetDistance` 变量的值(例如,对于米制,1毫米应为0.001)。 |
| **点击容差** | 用户点击可能不完全在线上。`GetParameterAtPoint` 方法本身有一定的容差。对于更精确的控制,可以先使用 `GetClosestPointTo` 方法将点击点投影到多段线上,再使用投影点进行计算。 |
| **复杂多段线** | 对于包含圆弧段的多段线,上述基于直线段方向向量的计算方法可能不精确。更通用的方法是使用 `GetPointAtDist` 和 `GetDistAtPoint` 方法,沿曲线路径进行距离计算。 |
| **事务处理** | 所有数据库操作(获取对象、修改、添加新对象)必须在事务 (`Transaction`) 内完成,这是 AutoCAD .NET API 的强制要求。 |
| **错误处理** | 生产代码中应增加 `try-catch` 块以处理可能的异常,例如参数计算错误或对象类型不匹配。 |
**优化后的打断点计算(适用于直线和圆弧段)**:
```csharp
// 替代上述第5步中的向量计算,使用沿曲线的距离进行计算
double distAtClickedPoint = pline.GetDistAtPoint(clickedPointOcs);
double dist1 = distAtClickedPoint - offsetDistance; // 向前1毫米
double dist2 = distAtClickedPoint + offsetDistance; // 向后1毫米
// 确保距离值有效(不小于0,不大于多段线总长)
dist1 = Math.Max(0, Math.Min(pline.Length, dist1));
dist2 = Math.Max(0, Math.Min(pline.Length, dist2));
// 获取打断点
Point3d breakPoint1 = pline.GetPointAtDist(dist1);
Point3d breakPoint2 = pline.GetPointAtDist(dist2);
// 获取对应的参数
double param1 = pline.GetParameterAtPoint(breakPoint1);
double param2 = pline.GetParameterAtPoint(breakPoint2);
此方法通过沿曲线的实际路径测量距离来计算打断点,对直线段和圆弧段都适用,是更健壮的解决方案。