ADN Open CIS
Сообщество программистов Autodesk в СНГ

29/08/2015

Части трубопроводной сети (трубы и колодцы) на виде профиля

На виде профиля, после добавления на него части трубопроводной сети (колодца или трубы), Civil 3D создает новый объект: ProfileViewPart. У этого объекта не много методов, но зато он является объектом базы данных чертежа (с ID и геометрией).
Итак, вопрос: как получить пикетаж и отметку части на виде профиля?
Используя габаритный контейнер части, мы можем получить доступ к координатам XY в модели. Тогда возможно получить среднюю точку (или какую-нибудь другую точку, например с максимальной и минимальной координатой Y). Используя эти координаты XY, мы можем вернуться обратно на вид профиля и запросить пикетаж и отметку для этой точки.
Пример кода ниже демонстрирует эту идею:

Код - C#: [Выделить]
  1.     // выбор части сети на виде профиля
  2.     Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  3.     PromptEntityOptions peo = new PromptEntityOptions(
  4.       "\nВыберите часть сети на виде профиля: ");
  5.     peo.SetRejectMessage("\nТолько части сети на виде профиля!");
  6.     peo.AddAllowedClass(typeof(ProfileViewPart), true);
  7.     PromptEntityResult per = ed.GetEntity(peo);
  8.     if (per.Status != PromptStatus.OK) return;
  9.     
  10.     Database db = Application.DocumentManager.MdiActiveDocument.Database;
  11.     using (Transaction trans = db.TransactionManager.StartTransaction())
  12.     {
  13.       // получение части сети, отображенной на виде профиля
  14.       ProfileViewPart partPV = trans.GetObject(per.ObjectId,
  15.         OpenMode.ForRead) as ProfileViewPart;
  16.       Part part = trans.GetObject(partPV.ModelPartId,
  17.         OpenMode.ForRead) as Part;
  18.     
  19.       // может иметься несколько видов профилей, отображающих эту часть...
  20.       ObjectIdCollection pvIds = part.GetProfileViewsDisplayingMe();
  21.       foreach (ObjectId pvId in pvIds)
  22.       {
  23.         // получаем среднюю точку этого колодца на виде профиля (зам. пер. – это может быть и труба)
  24.         // вы можете изменить эти координаты X,Y для максимальных или минимальных значений...
  25.         Extents3d ext = partPV.GeometricExtents;
  26.         double x = (ext.MaxPoint.X - ext.MinPoint.X) / 2 + ext.MinPoint.X;
  27.         double y = (ext.MaxPoint.Y - ext.MinPoint.Y) / 2 + ext.MinPoint.Y;
  28.     
  29.         // получение вида профиля
  30.         ProfileView pv = trans.GetObject(pvId, OpenMode.ForRead) as ProfileView;
  31.     
  32.         // и пикетаж с отметкой на виде профиля
  33.         double station = 0.0;
  34.         double elevation = 0.0;
  35.         pv.FindStationAndElevationAtXY(x, y, ref station, ref elevation);
  36.     
  37.         ed.WriteMessage(
  38.           "\n{0} отображается на виде профиля {1} на пикете: {2:0.00} | Отметка: {3:0.00}",
  39.           part.Name, pv.Name, station, elevation);
  40.       }
  41.     }

 

Примечание переводчика:

В результате проверки работы кода, обнаружилось, что в алгоритме имеется ошибка. Автор кода учел, что часть может отображаться на нескольких видах профилей. Однако, в этом случае, габаритный контейнер для части на виде профиля будет вычисляться охватыванием всех отображений части на всех видах профилей, т.к. это не несколько разных объектов, а один! Координаты габаритного контейнера получаются несколько иными, чем ожидается, и практического смысла от них мало. Подробно я показал это на видео: https://screencast.autodesk.com/main/details/4fba5135-8cd6-4949-988d-e3e6c239d99c.

В общем-то, использование габаритного контейнера для получения точек части сети на виде профиля – это довольно грубый способ. В конце концов, это же BIM-продукт! Мы имеем дело с интеллектуальными объектами! Почему бы не получать нужные свойства напрямую? Приведенный ниже код использует как раз такой, цивилизованный подход:

Код - C#: [Выделить]
  1.     // выбор части сети на виде профиля
  2.     Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  3.     PromptEntityOptions peo = new PromptEntityOptions(
  4.       "\nВыберите часть сети на виде профиля: ");
  5.     peo.SetRejectMessage("\nТолько части сети на виде профиля!");
  6.     peo.AddAllowedClass(typeof(ProfileViewPart), true);
  7.     PromptEntityResult per = ed.GetEntity(peo);
  8.     if (per.Status != PromptStatus.OK) return;
  9.     
  10.     Database db = Application.DocumentManager.MdiActiveDocument.Database;
  11.     using (Transaction trans = db.TransactionManager.StartTransaction())
  12.     {
  13.         // получение части сети, отображенной на виде профиля
  14.         ProfileViewPart partPV = trans.GetObject(per.ObjectId,
  15.           OpenMode.ForRead) as ProfileViewPart;
  16.         Part part = trans.GetObject(partPV.ModelPartId,
  17.           OpenMode.ForRead) as Part;
  18.     
  19.         // может иметься несколько видов профилей, отображающих эту часть...
  20.         ObjectIdCollection pvIds = part.GetProfileViewsDisplayingMe();
  21.         foreach (ObjectId pvId in pvIds)
  22.         {
  23.             // получение вида профиля
  24.             ProfileView pv = trans.GetObject(pvId, OpenMode.ForRead) as ProfileView;
  25.     
  26.             // получение трассы вида профиля
  27.             Alignment align = trans.GetObject(pv.AlignmentId, OpenMode.ForRead) as Alignment;
  28.     
  29.             // если объект - колодец
  30.             if (part is Structure)
  31.             {
  32.                 // получение колодца
  33.                 Structure structure = part as Structure;
  34.     
  35.                 // получение точки вставки колодца в модели
  36.                 Point3d strLoc = structure.Location;
  37.     
  38.                 // получение пикетажа колодца по трассе вида профиля
  39.                 // как побочные данные, будет получено еще смещение
  40.                 // колодца от трассы вида профиля в плане
  41.                 double
  42.                     station = 0.0,
  43.                     offset = 0.0;                       
  44.                 align.StationOffset(strLoc.X, strLoc.Y, ref station, ref offset);                
  45.     
  46.                 // вывод сообщения о положении колодца
  47.                 ed.WriteMessage(
  48.                   "\nКолодец '{0}' отображается на виде профиля '{1}' на пикете: {2:0.00}",
  49.                   part.Name, pv.Name, station);
  50.     
  51.                 // если колодец соединительный - вывод отметки его крышки и дна
  52.                 if (structure.PartType == PartType.StructJunction)
  53.                 {
  54.                     ed.WriteMessage
  55.                         ("\nОтметка крышки колодца: {0:0.00}, дна: {1:0.00}",
  56.                         structure.RimElevation, structure.SumpElevation);
  57.                 }
  58.             }
  59.             // если объект - труба
  60.             else if (part is Pipe)
  61.             {
  62.                 // получение трубы
  63.                 Pipe pipe = part as Pipe;
  64.     
  65.                 // ... и ее начальной и конечной точек (на оси трубы)
  66.                 Point3d
  67.                     startPt = pipe.StartPoint,
  68.                     endPt = pipe.EndPoint;
  69.                            
  70.                 // получение пикетажей и смещений начальной и конечной точек
  71.                 double
  72.                     startStation = 0.0,
  73.                     startOffset = 0.0,
  74.                     endStation = 0.0,
  75.                     endOffset = 0.0;
  76.     
  77.                 align.StationOffset(startPt.X, startPt.Y, ref startStation, ref startOffset);
  78.                 align.StationOffset(endPt.X, endPt.Y, ref endStation, ref endOffset);
  79.     
  80.                 // вывод значения пикетажей и отметок начальной и конечной точек
  81.                 ed.WriteMessage(
  82.                   "\nТруба '{0}' отображается на виде профиля '{1}'."
  83.                   + "\nНачало - пикет: {2:0.00}, отметка: {3:0.00}"
  84.                   + "\nКонец - пикет: {4:0.00}, отметка: {5:0.00}",
  85.                   part.Name, pv.Name, startStation, startPt.Z, endStation, endPt.Z);
  86.             }
  87.         }
  88.     }    

PViewPart.dwg

Источник: http://adndevblog.typepad.com/infrastructure/2014/07/pipe-network-parts-on-profile-view.html

Автор перевода: Дмитрий Загорулькин

Обсуждение: http://adn-cis.org/forum/index.php?topic=2961

Опубликовано 29.08.2015
Отредактировано 30.08.2015 в 15:02:42