Civil 3D. Создание новой ТП на трассе для трубопроводной сети в заданном пикете.

Автор Тема: Civil 3D. Создание новой ТП на трассе для трубопроводной сети в заданном пикете.  (Прочитано 2147 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 1983
  • Карма: 500
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
С помощью инструментов пользовательского интерфейса редактирования трассы, мы легко можем добавить на нее точку пересечения (ТП). Однако в API Civil 3D 2013-2016 нет никакого готового метода, позволяющего выполнить то же самое программно. Мне же был крайне необходим такой метод для автоматизации работы с видами профилей трубопроводных сетей, поэтому пришлось разрабатывать его самостоятельно.
В общем случае, эта задача крайне непроста. Достаточно взглянуть на список возможных типов объектов, которые могут входить в состав трассы:
Код - C# [Выбрать]
  1. public enum AlignmentEntityType
  2. {
  3.     Line = 257,
  4.     Arc = 258,
  5.     Spiral = 259,
  6.     SpiralCurveSpiral = 260,
  7.     SpiralLineSpiral = 261,
  8.     SpiralLine = 262,
  9.     LineSpiral = 263,
  10.     SpiralCurve = 264,
  11.     CurveSpiral = 265,
  12.     SpiralSpiralCurveSpiralSpiral = 266,
  13.     MultipleSegments = 267,
  14.     SpiralCurveSpiralCurveSpiral = 268,
  15.     SpiralCurveSpiralSpiralCurveSpiral = 269,
  16.     SpiralSpiral = 270,
  17.     SpiralSpiralCurve = 271,
  18.     CurveSpiralSpiral = 272,
  19.     CurveLineCurve = 273,
  20.     CurveReverseCurve = 274,
  21.     CurveCurveReverseCurve = 275,
  22. }

Но в случае с трубопроводной сетью, нужно обработать только объекты типа «Line» и «Arc», т.к. трубы можно создать только прямые или дуговые. Вдобавок, трасса для объектов трубопроводной сети не имеет «плавающих» составляющих. Значит, не придется рассматривать все эти варианты:
Код - C# [Выбрать]
  1. public enum AlignmentEntityConstraintType
  2. {
  3.     Fixed = 289,
  4.     FloatOnPrev = 290,
  5.     FloatOnNext = 291,
  6.     Free = 292,
  7. }
Таким образом, у нас имеются ограничения:
•   AlignmentEntityType – Line и Arc
•   AlignmentEntityConstraintType – Fixed
Ниже представлен код, решающий поставленную задачу:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using Autodesk.Civil.ApplicationServices;
  7. using Autodesk.Civil.DatabaseServices;
  8. using System;
  9. using System.Linq;
  10.  
  11. namespace DZagorulkin.CivilExtension
  12. {
  13.     public class TestCommandClass
  14.     {
  15.         [CommandMethod("TestAddPI")]
  16.         public void AlignmentAddPITest()
  17.         {
  18.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  19.             Database db = adoc.Database;
  20.             Editor ed = adoc.Editor;
  21.  
  22.             PromptEntityOptions alignOpt = new PromptEntityOptions("\nВыберите трассу: ");
  23.             alignOpt.SetRejectMessage("\nЭто не трасса!");
  24.             alignOpt.AddAllowedClass(typeof(Alignment), true);
  25.  
  26.             PromptEntityResult alignRes = ed.GetEntity(alignOpt);
  27.             if (alignRes.Status != PromptStatus.OK) return;
  28.  
  29.             PromptDoubleResult newPiStationRes = ed.GetDouble("\nПикетаж для добавления ТП: ");
  30.             if (newPiStationRes.Status != PromptStatus.OK) return;
  31.  
  32.             bool ok;
  33.  
  34.             using (Transaction tr = db.TransactionManager.StartTransaction())
  35.             {
  36.                 Alignment align = tr.GetObject
  37.                     (alignRes.ObjectId, OpenMode.ForWrite, false, true) as Alignment;
  38.                 ok = align.AddPIToFixedSubEntity(newPiStationRes.Value);
  39.                 tr.Commit();
  40.             }
  41.  
  42.             ed.WriteMessage
  43.                 ("\nТП на пикете {0:0.00} {1}.",
  44.                 newPiStationRes.Value,
  45.                 ok ? "создана" : "создать не удалось");
  46.         }
  47.     }
  48.  
  49.     public static class AlignmentSupport
  50.     {
  51.         /// <summary>
  52.         /// Добавление точки пересечения (ТП)
  53.         /// на фиксированном участке трассы
  54.         /// </summary>
  55.         /// <param name="alignment">Трасса</param>
  56.         /// <param name="station">Пикет, в котором добавляем точку</param>
  57.         public static bool AddPIToFixedSubEntity(this Alignment alignment, double station)
  58.         {
  59.             // Координаты точки - будущей ТП
  60.             Point2d point;
  61.             // Если трасса не содержит еще ТП в указаном пикете
  62.             if (!alignment.GetStationSet(StationTypes.GeometryPoint)
  63.                 .Any(stat => stat.RawStation.Equals(station))
  64.                 // и точка находится на трассе
  65.                 && GetPointAtStation(alignment, station, out point))
  66.             {
  67.                 // Проходим по всем объектам трассы, пока не найдем объект,
  68.                 // на котором наша точка
  69.                 for (int i = 0; i < alignment.Entities.Count; i++)
  70.                 {
  71.                     AlignmentEntity alignEnt = alignment.Entities[i];
  72.  
  73.                     // Если объект имеет нефиксированный тип - пропускаем его
  74.                     if (alignEnt.Constraint1 != AlignmentEntityConstraintType.Fixed) continue;
  75.  
  76.                     // Если объект - отрезок
  77.                     if (alignEnt.EntityType == AlignmentEntityType.Line)
  78.                     {
  79.                         // Приводим его к типу "отрезок трассы"
  80.                         AlignmentLine alignLine = alignEnt as AlignmentLine;
  81.                         // Получаем координаты начала и конца
  82.                         Point2d startPt = alignLine.StartPoint;
  83.                         Point2d endPt = alignLine.EndPoint;
  84.  
  85.                         // Если добавляемая точка находится на этом отрезке
  86.                         if (Math.Min(alignLine.StartStation, alignLine.EndStation) < station
  87.                             && station < Math.Max(alignLine.StartStation, alignLine.EndStation))
  88.                         {
  89.                             // Создаем вместо одного отрезка два
  90.                             alignment.Entities.AddFixedLine
  91.                                 (new Point3d(startPt.X, startPt.Y, 0.0),
  92.                                 new Point3d(point.X, point.Y, 0.0));
  93.                             alignment.Entities.AddFixedLine
  94.                                 (new Point3d(point.X, point.Y, 0.0),
  95.                                 new Point3d(endPt.X, endPt.Y, 0.0));
  96.                             // Удаляем исходный отрезок
  97.                             alignment.Entities.Remove(alignEnt);
  98.                             return true;
  99.                         }
  100.                     }
  101.                     // Если объект - дуга
  102.                     else if (alignEnt.EntityType == AlignmentEntityType.Arc)
  103.                     {
  104.                         // Приводим его к типу "дуга трассы"
  105.                         AlignmentArc alignArc = alignEnt as AlignmentArc;
  106.  
  107.                         // Получаем среднюю точку дуги трассы
  108.                         Point2d midPoint;
  109.                         GetPointAtStation
  110.                             (alignment,
  111.                             (alignArc.EndStation + alignArc.StartStation) / 2,
  112.                             out midPoint);
  113.  
  114.                         // Проверяем, находится ли наша точка на этой дуге.
  115.                         if (Math.Min(alignArc.StartStation, alignArc.EndStation) < station
  116.                             && station < Math.Max(alignArc.StartStation, alignArc.EndStation))
  117.                         {
  118.                             // Получаем средние точки будущих трасс
  119.                             Point3d midFirstArc, midSecondArc;
  120.  
  121.                             using (CircularArc2d arc
  122.                                 = new CircularArc2d(alignArc.StartPoint, midPoint, alignArc.EndPoint))
  123.                             {
  124.  
  125.                                 double
  126.                                     paramStart = arc.GetParameterOf(alignArc.StartPoint),
  127.                                     paramEnd = arc.GetParameterOf(alignArc.EndPoint),
  128.                                     paramPt = arc.GetParameterOf(point);
  129.  
  130.                                 Point2d pt1 = arc.EvaluatePoint((paramPt + paramStart) * 0.5);
  131.                                 midFirstArc = new Point3d(pt1.X, pt1.Y, 0.0);
  132.  
  133.                                 Point2d pt2 = arc.EvaluatePoint((paramPt + paramEnd) * 0.5);
  134.                                 midSecondArc = new Point3d(pt2.X, pt2.Y, 0.0);
  135.                             }                            
  136.  
  137.                             // Создаем вместо одной дуги две
  138.                             AlignmentArc newFirstArc = alignment.Entities.AddFixedCurve
  139.                                (alignArc.EntityBefore,
  140.                                new Point3d(alignArc.StartPoint.X, alignArc.StartPoint.Y, 0.0),
  141.                                midFirstArc, new Point3d(point.X, point.Y, 0.0));
  142.                             alignment.Entities.AddFixedCurve
  143.                                 (newFirstArc.EntityId, new Point3d(point.X, point.Y, 0.0), midSecondArc,
  144.                                 new Point3d(alignArc.EndPoint.X, alignArc.EndPoint.Y, 0.0));
  145.                             // Удаляем исходную дугу
  146.                             alignment.Entities.Remove(alignEnt);
  147.                             return true;
  148.                         }
  149.                     }
  150.                 }
  151.             }
  152.  
  153.             return false;
  154.         }
  155.  
  156.         /// <summary>
  157.         /// Вспомогательный метод получения точки на трассе в указанном пикете
  158.         /// </summary>
  159.         /// <param name="alignment">Трасса</param>
  160.         /// <param name="station">Пикет</param>
  161.         /// <param name="stationPoint">Переменная для сохранения точки</param>
  162.         /// <returns>True - пикетаж задан верно, false - пикет вне трассы</returns>
  163.         static bool GetPointAtStation
  164.             (Alignment alignment, double station, out Point2d stationPoint)
  165.         {
  166.             // Если пикетаж в границах трассы
  167.             if (alignment.StartingStation <= station
  168.                 && station <= alignment.EndingStation)
  169.             {
  170.                 // Получаем 3D точку на пикете
  171.                 Point3d pt = alignment.GetPointAtDist
  172.                     (station - alignment.StartingStation);
  173.  
  174.                 // Конвертируем ее в 2D
  175.                 stationPoint = new Point2d(pt.X, pt.Y);
  176.  
  177.                 return true;
  178.             }
  179.             stationPoint = new Point2d();
  180.             return false;
  181.         }
  182.     }
  183. }
  184.  
« Последнее редактирование: 12-09-2015, 12:43:05 от Дмитрий Загорулькин »

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 785
  • Карма: 124
Off-Topic: показать
На всякий случай: в заголовке статьи укажи полное название и версию ПО, для которого выполняешь разработку. Я, например, могу только подозревать, что разговор ведется про Civil3D 2014-2016, но не уверен :)
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 1983
  • Карма: 500
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Спасибо, принято :)
Версия в заголовок уже не вмещается.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 9497
  • Карма: 1201
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение