求助,万能的网友
以下是一段沿路径阵列的代码,程序总是出错,我的需求是:
1.修正代码(平台为AutoCAD 2014)
2.添加一个界面窗口,类似于3dmax中的间隔工具。

网友答: 我先来,AI生成的就让AI去完善
网友答:
人家都没有说时ai生产的啊
网友答:
感觉就很像
网友答:
代码质量越来越差了,连tr.GetObject(id)都不放using了...
而且开了n个事务,还混开了 StartOpenCloseTransaction...
不知道怎么评价网友答: 楼主 这个代码怎么加载到CAD里 没接触过 求教网友答: 本帖最后由 你有种再说一遍 于 2026-1-4 17:59 编辑
去b站搜cad c#二次开发,需要下载vs(不是vs code),编译为dll.
以下是一段沿路径阵列的代码,程序总是出错,我的需求是:
1.修正代码(平台为AutoCAD 2014)
2.添加一个界面窗口,类似于3dmax中的间隔工具。

- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.DatabaseServices;
- using Autodesk.AutoCAD.EditorInput;
- using Autodesk.AutoCAD.Geometry;
- using Autodesk.AutoCAD.Runtime;
- using System;
- namespace AutoCADCommands
- {
- public class PathArrayCommand
- {
- // 1. 定义常驻程序的阵列参数变量
- private static string arrayMethod = "Measure"; // 阵列方法,默认为测量方式
- private static double arraySpacing = 5.0; // 阵列间距,默认为5.0
- private static int arrayCount = 5; // 阵列数量,默认为5
- private static double pathStartOffset = 0.0; // 始端偏移距离,默认为0.0
- private static double pathEndOffset = 0.0; // 末端偏移距离,默认为0.0
- private static bool rotateWithPath = true; // 是否旋转至切线方向,默认为true
- [CommandMethod("PATHARRAY")]
- public static void PathArray()
- {
- var doc = Application.DocumentManager.MdiActiveDocument;
- var db = doc.Database;
- var ed = doc.Editor;
- try
- {
- // 2. 选择要阵列的对象
- PromptSelectionOptions selOptions = new PromptSelectionOptions();
- selOptions.MessageForAdding = "\n选择要阵列的对象: ";
- PromptSelectionResult selectionResult = ed.GetSelection(selOptions);
- if (selectionResult.Status != PromptStatus.OK)
- {
- ed.WriteMessage("\n未选择对象,命令取消。");
- return; // 未选择对象,退出程序
- }
- // 计算选择对象的中心点(只考虑二维平面)
- Point3d selectionCenter = Point3d.Origin;
- bool hasValidEntity = false;
- double minX = 0, minY = 0, maxX = 0, maxY = 0;
- using (Transaction tr = db.TransactionManager.StartTransaction())
- {
- try
- {
- ObjectId[] objectIds = selectionResult.Value.GetObjectIds();
-
- // 遍历所有选中的对象,计算二维边界框
- for (int i = 0; i < objectIds.Length; i++)
- {
- try
- {
- Entity entity = tr.GetObject(objectIds, OpenMode.ForRead) as Entity;
- if (entity != null && entity.Bounds.HasValue)
- {
- Extents3d extents = entity.Bounds.Value;
- // 只考虑二维坐标
- double entityMinX = extents.MinPoint.X;
- double entityMinY = extents.MinPoint.Y;
- double entityMaxX = extents.MaxPoint.X;
- double entityMaxY = extents.MaxPoint.Y;
- if (!hasValidEntity)
- {
- // 第一个有效对象,初始化边界值
- minX = entityMinX;
- minY = entityMinY;
- maxX = entityMaxX;
- maxY = entityMaxY;
- hasValidEntity = true;
- }
- else
- {
- // 更新最小值和最大值
- if (entityMinX < minX) minX = entityMinX;
- if (entityMinY < minY) minY = entityMinY;
- if (entityMaxX > maxX) maxX = entityMaxX;
- if (entityMaxY > maxY) maxY = entityMaxY;
- }
- }
- }
- catch
- {
- // 忽略无法处理的实体
- continue;
- }
- }
- }
- catch (Autodesk.AutoCAD.Runtime.Exception ex)
- {
- ed.WriteMessage("\n计算中心点时出错:" + ex.Message);
- selectionCenter = new Point3d(0, 0, 0);
- }
- tr.Commit();
- }
- if (hasValidEntity)
- {
- // 计算二维几何中心点,Z坐标为0
- double centerX = (minX + maxX) / 2.0;
- double centerY = (minY + maxY) / 2.0;
- selectionCenter = new Point3d(centerX, centerY, 0.0);
- }
- else
- {
- ed.WriteMessage("\n未找到有效对象或对象没有边界框。");
- return;
- }
- // 3. 指定阵列基点<中心点>
- PromptPointOptions basePointOptions = new PromptPointOptions("\n指定阵列基点,或<中心点(Enter)>: ");
- basePointOptions.AllowNone = true;
- basePointOptions.UseBasePoint = true;
- basePointOptions.BasePoint = selectionCenter;
- PromptPointResult basePointResult = ed.GetPoint(basePointOptions);
- Point3d basePoint;
- if (basePointResult.Status == PromptStatus.Cancel)
- {
- ed.WriteMessage("\n命令已取消。");
- return;
- }
- else if (basePointResult.Status == PromptStatus.None)
- {
- // 用户按了Enter,使用计算出的中心点
- basePoint = selectionCenter;
- }
- else if (basePointResult.Status == PromptStatus.OK)
- {
- // 用户指定了点,使用该点
- basePoint = basePointResult.Value;
- // 确保Z坐标为0(二维平面)
- basePoint = new Point3d(basePoint.X, basePoint.Y, 0.0);
- }
- else
- {
- // 其他状态,使用默认中心点
- basePoint = selectionCenter;
- }
- // 4. 显示当前阵列参数并提示用户修改
- bool continueEditingParams = true;
- while (continueEditingParams)
- {
- try
- {
- // 显示当前参数
- string offsetInfo = "始端偏移<" + pathStartOffset.ToString("F2") + ">,末端偏移<" + pathEndOffset.ToString("F2") + ">,旋转< " + (rotateWithPath ? "是" : "否") + ">";
- if (arrayMethod == "Measure")
- {
- ed.WriteMessage("\n当前阵列参数:按间距<" + arraySpacing.ToString("F2") + ">," + offsetInfo);
- }
- else
- {
- ed.WriteMessage("\n当前阵列参数:按数量<" + arrayCount.ToString() + ">," + offsetInfo);
- }
- // 提示用户选择参数选项
- PromptKeywordOptions paramOptions = new PromptKeywordOptions("\n选择阵列参数[间距(Distance)/数量(Count)/始端偏移(Start)/末端偏移(End)/旋转(Rotate)]<确定(Enter)>: ");
- paramOptions.Keywords.Add("Distance");
- paramOptions.Keywords.Add("Count");
- paramOptions.Keywords.Add("Start");
- paramOptions.Keywords.Add("End");
- paramOptions.Keywords.Add("Rotate");
- paramOptions.AllowNone = true; //按 ENTER 键(NULL 输入)时使用默认值
- paramOptions.Keywords.Default = "None";
- PromptResult paramResult = ed.GetKeywords(paramOptions);
- if (paramResult.Status == PromptStatus.OK)
- {
- switch (paramResult.StringResult)
- {
- case "Distance": // 设置间距
- PromptDistanceOptions spacingOptions = new PromptDistanceOptions("\n指定间距 <" + arraySpacing.ToString("F2") + ">: ");
- spacingOptions.DefaultValue = arraySpacing;
- spacingOptions.AllowNegative = false;
- spacingOptions.AllowZero = false;
- spacingOptions.UseBasePoint = true;
- spacingOptions.BasePoint = basePoint;
- PromptDoubleResult spacingResult = ed.GetDistance(spacingOptions);
- if (spacingResult.Status == PromptStatus.OK)
- {
- arraySpacing = spacingResult.Value;
- arrayMethod = "Measure"; // 切换到测量方式
- }
- break;
- case "Count": // 设置数量
- PromptIntegerOptions countOptions = new PromptIntegerOptions("\n输入数量 <" + arrayCount + ">: ");
- countOptions.DefaultValue = arrayCount;
- countOptions.LowerLimit = 2;
- PromptIntegerResult countResult = ed.GetInteger(countOptions);
- if (countResult.Status == PromptStatus.OK)
- {
- arrayCount = countResult.Value;
- arrayMethod = "Count"; // 切换到等分方式
- }
- break;
- case "Start": // 设置始端偏移
- PromptDistanceOptions startOffsetOptions = new PromptDistanceOptions("\n指定始端偏移距离 <" + pathStartOffset.ToString("F2") + ">: ");
- startOffsetOptions.DefaultValue = pathStartOffset;
- startOffsetOptions.AllowNegative = false; // 不允许负值,只能从起点向后偏移
- PromptDoubleResult startOffsetResult = ed.GetDistance(startOffsetOptions);
- if (startOffsetResult.Status == PromptStatus.OK)
- {
- pathStartOffset = startOffsetResult.Value;
- }
- break;
- case "End": // 设置末端偏移
- PromptDistanceOptions endOffsetOptions = new PromptDistanceOptions("\n指定末端偏移距离 <" + pathEndOffset.ToString("F2") + ">: ");
- endOffsetOptions.DefaultValue = pathEndOffset;
- endOffsetOptions.AllowNegative = false; // 不允许负值,只能从终点向前偏移
- PromptDoubleResult endOffsetResult = ed.GetDistance(endOffsetOptions);
- if (endOffsetResult.Status == PromptStatus.OK)
- {
- pathEndOffset = endOffsetResult.Value;
- }
- break;
- case "Rotate": // 切换旋转选项
- rotateWithPath = !rotateWithPath;
- ed.WriteMessage("\n路径旋转已" + (rotateWithPath ? "开启" : "关闭"));
- break;
- }
- }
- else if (paramResult.Status == PromptStatus.None)
- {
- continueEditingParams = false; // 用户按回车,结束参数设置
- }
- else
- {
- ed.WriteMessage("\n用户取消,退出程序。");
- return;
- }
- }
- catch (Autodesk.AutoCAD.Runtime.Exception ex)
- {
- ed.WriteMessage("\n参数设置时出错:" + ex.Message);
- continueEditingParams = false;
- }
- }
- // 5. 开始路径阵列循环
- bool continueArray = true;
- while (continueArray)
- {
- try
- {
- // 点选一条路径
- PromptEntityOptions pathOptions = new PromptEntityOptions("\n选择路径: ");
- pathOptions.SetRejectMessage("\n所选对象不是有效路径。");
- pathOptions.AddAllowedClass(typeof(Curve), false);
- PromptEntityResult pathResult = ed.GetEntity(pathOptions);
- if (pathResult.Status == PromptStatus.Cancel)
- {
- ed.WriteMessage("\n命令取消。");
- break;
- }
- else if (pathResult.Status != PromptStatus.OK)
- {
- break; // 未选择路径,结束循环
- }
- // 检查是否为有效路径(排除构造线和射线)
- using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
- {
- DBObject obj = tr.GetObject(pathResult.ObjectId, OpenMode.ForRead);
- string dxfName = obj.GetType().Name;
- if (dxfName == "Xline" || dxfName == "Ray")
- {
- ed.WriteMessage("\n构造线和射线不能作为路径。");
- continue;
- }
- }
- // 沿该路径创建对象阵列
- if (!CreatePathArray(db, ed, basePoint, selectionResult.Value.GetObjectIds(),pathResult.ObjectId))
- {
- ed.WriteMessage("\n阵列创建失败。");
- }
- // 询问是否继续
- PromptKeywordOptions continueOptions = new PromptKeywordOptions("\n是否继续阵列? [是(Y)/否(N)] <是>: ");
- continueOptions.Keywords.Add("Y");
- continueOptions.Keywords.Add("N");
- continueOptions.AllowNone = true;
- continueOptions.Keywords.Default = "Y";
- PromptResult continueResult = ed.GetKeywords(continueOptions);
- if (continueResult.Status == PromptStatus.Cancel)
- {
- ed.WriteMessage("\n命令取消。");
- continueArray = false;
- }
- else if (continueResult.Status != PromptStatus.OK ||
- (continueResult.StringResult == "N" ||
- (continueResult.Status == PromptStatus.None && continueResult.StringResult != "Y")))
- {
- continueArray = false;
- }
- }
- catch (Autodesk.AutoCAD.Runtime.Exception ex)
- {
- ed.WriteMessage("\n阵列过程中出错: " +ex.Message);
- continueArray = false;
- }
- }
- ed.WriteMessage("\n路径阵列完成。");
- }
- catch (System.Runtime.InteropServices.SEHException sehEx)
- {
- ed.WriteMessage("\n系统异常: 请确保选择的对象类型正确。");
- Application.DocumentManager.MdiActiveDocument.SendStringToExecute("(princ)\n", true, false, false);
- }
- catch (Autodesk.AutoCAD.Runtime.Exception ex)
- {
- ed.WriteMessage("\n命令执行时发生错误: " +ex.Message);
- Application.DocumentManager.MdiActiveDocument.SendStringToExecute("(princ)\n", true, false, false);
- }
- }
- // 创建路径阵列的辅助方法(二维平面)
- private static bool CreatePathArray(Database db, Editor ed, Point3d basePoint,
- ObjectId[] sourceIds, ObjectId pathId)
- {
- using (Transaction tr = db.TransactionManager.StartTransaction())
- {
- try
- {
- // 获取路径曲线
- Curve path = tr.GetObject(pathId, OpenMode.ForRead) as Curve;
- if (path == null)
- {
- ed.WriteMessage("\n无法获取路径对象。");
- return false;
- }
- // 获取路径长度(二维平面)
- double totalLength = 0;
- try
- {
- totalLength = path.GetDistanceAtParameter(path.EndParam);
- }
- catch
- {
- // 对于某些类型的曲线,使用替代方法
- try
- {
- //totalLength = path.GetDistanceAtPoint(path.EndPoint);
- totalLength = path.GetDistAtPoint(path.EndPoint);
- }
- catch
- {
- ed.WriteMessage("\n无法计算路径长度。");
- return false;
- }
- }
- // 应用始端和末端偏移
- double effectiveLength = totalLength - pathStartOffset - pathEndOffset;
- if (effectiveLength <= 0)
- {
- ed.WriteMessage("\n路径长度不足或偏移量过大。");
- return false;
- }
- // 根据阵列方法计算元素位置
- double[] positions;
- if (arrayMethod == "Count") // 等分方式
- {
- if (arrayCount < 2)
- {
- ed.WriteMessage("\n阵列数量必须大于1。");
- return false;
- }
- positions = new double[arrayCount];
- double interval = effectiveLength / (arrayCount - 1);
- for (int i = 0; i < arrayCount; i++)
- {
- positions = pathStartOffset + i * interval;
- }
- }
- else // 测量方式
- {
- if (arraySpacing <= 0)
- {
- ed.WriteMessage("\n阵列间距必须大于0。");
- return false;
- }
- int count = (int)(effectiveLength / arraySpacing) + 1;
- if (count < 2) count = 2;
- positions = new double[count];
- for (int i = 0; i < count; i++)
- {
- positions = pathStartOffset + i * arraySpacing;
- }
- }
- // 获取路径起点处的切线方向(用于旋转参考)
- double startRotation = 0;
- if (rotateWithPath)
- {
- try
- {
- double startParam = path.GetParameterAtDistance(pathStartOffset);
- Vector3d startTangent = path.GetFirstDerivative(startParam).GetNormal();
- // 二维平面旋转,只考虑XY平面
- startRotation = Math.Atan2(startTangent.Y, startTangent.X);
- }
- catch
- {
- // 如果无法获取切线方向,使用默认值
- startRotation = 0;
- }
- }
- // 创建源对象的ID集合
- ObjectIdCollection sourceIdCollection = new ObjectIdCollection(sourceIds);
- // 沿路径创建每个阵列副本
- for (int i = 0; i < positions.Length; i++)
- {
- double distance = positions;
- // 确保距离在路径范围内
- if (distance < 0 || distance > totalLength)
- continue;
- // 获取路径上的点
- Point3d pointOnPath;
- try
- {
- pointOnPath = path.GetPointAtDist(distance);
- // 确保点在二维平面
- pointOnPath = new Point3d(pointOnPath.X, pointOnPath.Y, 0.0);
- }
- catch
- {
- // 如果距离超出范围,跳过
- continue;
- }
- // 克隆源对象
- IdMapping mapping = new IdMapping();
- db.DeepCloneObjects(sourceIdCollection, db.CurrentSpaceId, mapping, false);
- // 对克隆的对象应用变换
- foreach (IdPair pair in mapping)
- {
- if (pair.IsCloned && pair.IsPrimary)
- {
- Entity clonedEntity = tr.GetObject(pair.Value, OpenMode.ForWrite) as Entity;
- if (clonedEntity != null)
- {
- // 1. 从基点平移到路径点(二维平移)
- Vector3d translation = basePoint.GetVectorTo(pointOnPath);
- Matrix3d transform = Matrix3d.Displacement(translation);
- // 2. 如果需要,旋转至切线方向(二维旋转)
- if (rotateWithPath)
- {
- try
- {
- double currentParam = path.GetParameterAtDistance(distance);
- Vector3d currentTangent = path.GetFirstDerivative(currentParam).GetNormal();
- // 二维平面旋转角度
- double currentRotation = Math.Atan2(currentTangent.Y, currentTangent.X);
- double rotationAngle = currentRotation - startRotation;
- // 以路径点为中心旋转(Z轴旋转)
- if (Math.Abs(rotationAngle) > 1e-10) // 避免微小旋转
- {
- transform = transform *
- Matrix3d.Rotation(rotationAngle, Vector3d.ZAxis, pointOnPath);
- }
- }
- catch
- {
- // 如果无法计算旋转,继续执行平移
- }
- }
- // 应用变换
- clonedEntity.TransformBy(transform);
- }
- }
- }
- }
- tr.Commit();
- return true;
- }
- catch (System.Runtime.InteropServices.SEHException sehEx)
- {
- ed.WriteMessage("\n系统异常: 路径操作失败。");
- return false;
- }
- catch (Autodesk.AutoCAD.Runtime.Exception ex)
- {
- ed.WriteMessage("\n创建阵列时出错:"+ ex.Message);
- return false;
- }
- }
- }
- }
- }
- if (entity != null && entity.Bounds.HasValue)
网友答: 我先来,AI生成的就让AI去完善
网友答:
tranque 发表于 2026-1-4 12:23
我先来,AI生成的就让AI去完善
人家都没有说时ai生产的啊
网友答:
qifeifei 发表于 2026-1-4 14:09
人家都没有说时ai生产的啊
感觉就很像
网友答:
代码质量越来越差了,连tr.GetObject(id)都不放using了...而且开了n个事务,还混开了 StartOpenCloseTransaction...
不知道怎么评价网友答: 楼主 这个代码怎么加载到CAD里 没接触过 求教网友答: 本帖最后由 你有种再说一遍 于 2026-1-4 17:59 编辑
小鸟 发表于 2026-1-4 17:55
楼主 这个代码怎么加载到CAD里 没接触过 求教
去b站搜cad c#二次开发,需要下载vs(不是vs code),编译为dll.