欢迎来到我的博客
Civil 3D开发与应用,欢迎加入QQ群:484124761
AutoCAD开发,欢迎加入QQ群:193522571

要素线高程修改c#版

自己之前写过lisp版的,

居然全忘了,

上周五(2026年1月23日)用到这个功能,

让ai写程序,

写的乱七八糟,

达不到预期,

于是自己又写了c#程序(压根就没想到自己之前的lisp代码)

Civil 3d 要素线高程缩放 - david96007 - 博客园

 

因为时间仓促,
程序中的bug并没有被发现,
今天再次测试,
找到了bug,
让ai给修改了一下(lisp程序也完善了一下),
现在把完整代码贴在此,
万一哪一天ai搜索,
也能提供一点儿信息!

(代码未经测试)

 public void MyCommand_TT() // This method can have any name
 {
     Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
     Database db = Application.DocumentManager.MdiActiveDocument.Database;

     // 创建选择过滤器,只允许选择要素线
     TypedValue[] typval = new TypedValue[1];
     typval[0] = new TypedValue((int)DxfCode.Start, "AECC_FEATURE_LINE");
     SelectionFilter filter = new SelectionFilter(typval);

     // 提示用户选择要素线
     PromptSelectionOptions pso = new PromptSelectionOptions();
     pso.MessageForAdding = "\n选择要素线:";
     pso.MessageForRemoval = "\n移除要素线:";
     PromptSelectionResult psr = ed.GetSelection(pso, filter);

     if (psr.Status != PromptStatus.OK)
         return;

     // 新增:让用户输入缩放系数(替代固定的0.3048)
     PromptDoubleOptions pdo = new PromptDoubleOptions("\n请输入高程缩放系数 (默认0.3048):");
     pdo.AllowNegative = false; // 禁止负数
     pdo.AllowZero = false;     // 禁止0
     pdo.DefaultValue = 0.3048; // 默认值
     PromptDoubleResult pdr = ed.GetDouble(pdo);
     if (pdr.Status != PromptStatus.OK)
     {
         ed.WriteMessage("\n输入无效,操作取消。");
         return;
     }
     double factor = pdr.Value; // 使用用户输入的系数
     // 定义缩放系数(可根据需要修改,或改为用户输入)
     int modifiedCount = 0;

     // ========== 核心修改:第一步 - 批量备份所有要素线的原始高程 ==========
     // 存储结构:Key=要素线ObjectId,Value=该要素线所有点的原始高程列表
     Dictionary<ObjectId, List<double>> originalElevations = new Dictionary<ObjectId, List<double>>();
     // 先开启只读事务,批量提取所有点的原始高程(避免联动修改影响)
     using (Transaction readTr = db.TransactionManager.StartTransaction())
     {
         foreach (ObjectId id in psr.Value.GetObjectIds())
         {
             // 以只读方式打开要素线
             FeatureLine fl = readTr.GetObject(id, OpenMode.ForRead) as FeatureLine;
             if (fl == null) continue;

             // 获取所有点(包含高程)
             var pts = fl.GetPoints(FeatureLinePointType.AllPoints);
             List<double> elevList = new List<double>();

             // 计算有效点数(闭合要素线跳过最后一个点)
             int n = pts.Count;
             if (pts.Count > 0 && pts[0].DistanceTo(pts[n - 1]) < 1e-6)
             {
                 n = n - 1; // 闭合要素线,最后一个点与第一个点重合,跳过
             }

             // 备份前n个点的原始高程
             for (int i = 0; i < n; i++)
             {
                 elevList.Add(pts[i].Z); // 仅存储原始高程值
             }

             // 将备份数据存入字典
             originalElevations.Add(id, elevList);
         }
         readTr.Commit(); // 只读事务也需Commit释放资源
     }


     // ========== 第二步 - 基于备份的原始高程批量修改 ==========
     using (Transaction writeTr = db.TransactionManager.StartTransaction())
     {
         foreach (ObjectId id in psr.Value.GetObjectIds())
         {
             // 跳过无备份数据的要素线
             if (!originalElevations.ContainsKey(id)) continue;

             // 以写方式打开要素线
             FeatureLine fl = writeTr.GetObject(id, OpenMode.ForWrite) as FeatureLine;
             if (fl == null) continue;

             // 获取该要素线的原始高程备份
             List<double> elevList = originalElevations[id];
             int n = elevList.Count;

             // 遍历所有点,使用原始高程计算新值
             for (int i = 0; i < n; i++)
             {
                 // 基于原始高程计算新高程(仅乘一次系数,避免联动影响)
                 double newElevation = elevList[i] * factor;
                 // 设置新高程(即使点关联,也只按原始值修改一次)
                 fl.SetPointElevation(i, newElevation);
             }

             modifiedCount++;
         }

         writeTr.Commit(); // 提交修改
     }
     // 输出结果提示
     ed.WriteMessage($"\n已成功修改 {modifiedCount} 条要素线的高程,所有点高程乘以系数 {factor}。");
 }

 

posted @ 2026-01-26 16:58  david96007  阅读(1)  评论(0)    收藏  举报