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

05/09/2015

Переопределение частей трубопроводной сети на виде профиля

Используя эту простую заготовку переопределения, мы можем изменить отображение трубы или колодца на виде профиля. Нам нужно переопределить класс ProfileViewPart и добавить немного геометрии. Это простой пример:

Код - C#: [Выделить]
  1.     class PipePartOverrule : DrawableOverrule
  2.     {
  3.         public override bool WorldDraw(
  4.           Drawable drawable, WorldDraw wd)
  5.         {
  6.             bool ret = base.WorldDraw(drawable, wd);
  7.     
  8.             ProfileViewPart viewPart = drawable as ProfileViewPart;
  9.             if (viewPart == null) return ret; // для безопасности
  10.     
  11.             // получение базы данных
  12.             // если объект является объектом базы данных,
  13.             // получаем ее из свойства объекта
  14.             // если нет, получаем активную базу данных
  15.             Database db = (viewPart.Database != null ?
  16.               viewPart.Database :
  17.               Application.DocumentManager.
  18.               MdiActiveDocument.Database);
  19.     
  20.             // получение типа объекта в модели
  21.             if (viewPart.ModelPartId.ObjectClass ==
  22.               RXClass.GetClass(typeof(Pipe)))
  23.             {
  24.                 // хорошо, эта часть представляет собой трубу
  25.                 // нарисуем что-нибудь... пусть будет пересекающий отрезок
  26.                 wd.Geometry.WorldLine(
  27.                   viewPart.Bounds.Value.MinPoint,
  28.                   viewPart.Bounds.Value.MaxPoint);
  29.             }
  30.     
  31.             // если вам нужно обрабатывать колодцы
  32.             //else if (viewPart.ModelPartId.ObjectClass ==
  33.             //  RXClass.GetClass(typeof(Structure)))
  34.             //{
  35.             //}
  36.     
  37.             return ret;
  38.         }
  39.     }
  40.     
  41.     public class Commads
  42.     {
  43.         [CommandMethod("profilePartOverrule")]
  44.         public static void CmdProfilePartOverrule()
  45.         {
  46.             if (_overrule == null)
  47.             {
  48.                 _overrule = new PipePartOverrule();
  49.                 Overrule.AddOverrule(
  50.                   RXClass.GetClass(typeof(ProfileViewPart)),
  51.                   _overrule, false);
  52.             }
  53.             else
  54.             {
  55.                 Overrule.RemoveOverrule(
  56.                   RXClass.GetClass(typeof(ProfileViewPart)),
  57.                   _overrule);
  58.                 _overrule = null;
  59.             }
  60.             Application.DocumentManager.
  61.               MdiActiveDocument.Editor.Regen();
  62.         }
  63.     
  64.         private static PipePartOverrule _overrule = null;
  65.     }

От переводчика: Как мы уже видели ранее, метод работы с частями сети на виде профиля через габаритный контейнер очень груб и может применяться в ограниченных случаях – когда заранее известно, каким образом отображается часть и строго определено, что одна часть отображается только на одном виде профиля.

В коде ниже представлено, каким образом можно переопределять отображения частей трубопроводной сети более корректно:

Код - C#: [Выделить]
  1.     class MyPipePartOverrule : DrawableOverrule
  2.     {
  3.         public override bool WorldDraw(
  4.          Drawable drawable, WorldDraw wd)
  5.         {
  6.             // Выводим базовое отображение объекта
  7.             bool ret = base.WorldDraw(drawable, wd);
  8.     
  9.             ProfileViewPart viewPart = drawable as ProfileViewPart;
  10.             if (viewPart == null) return ret; // для безопасности
  11.     
  12.             // получение типа объекта в модели
  13.             if (viewPart.ModelPartId.ObjectClass ==
  14.               RXClass.GetClass(typeof(Pipe)))
  15.             {
  16.                 // Используем эмуляцию транзакции для работы с объектами
  17.                 using (Transaction tr = viewPart.ModelPartId.Database
  18.                     .TransactionManager.StartOpenCloseTransaction())
  19.                 {
  20.                     // Получаем объект трубы
  21.                     Pipe pipe = tr.GetObject(viewPart.ModelPartId, OpenMode.ForRead) as Pipe;
  22.     
  23.                     // Проходим по всем видам профилей, которые отображают трубу
  24.                     foreach (ObjectId pViewId in pipe.GetProfileViewsDisplayingMe())
  25.                     {
  26.                         // Проверяем существования вила профиля
  27.                         if (pViewId.IsValid && !pViewId.IsErased && !pViewId.IsEffectivelyErased)
  28.                         {
  29.                             // Получаем вид профиля
  30.                             ProfileView pView
  31.                                 = tr.GetObject(pViewId, OpenMode.ForRead) as ProfileView;
  32.     
  33.                             // Получаем трассу вида профиля
  34.                             Alignment align
  35.                                 = tr.GetObject(pView.AlignmentId, OpenMode.ForRead) as Alignment;
  36.     
  37.                             // Точка пересечения трубы и плоскости вида профиля
  38.                             Point3d intersPtAnPipe;
  39.     
  40.                             using (Point3dCollection ptsCol = new Point3dCollection())
  41.                             {
  42.                                 pipe.IntersectWith
  43.                                     (align,
  44.                                     Intersect.OnBothOperands,
  45.                                     ptsCol, new IntPtr(0), new IntPtr(0));
  46.     
  47.                                 // Если пересечений нет - переходим к следующему виду профиля
  48.                                 if (ptsCol.Count != 1) continue;
  49.     
  50.                                 // Точка пересечения, найденная в методе IntersectWith                               
  51.                                 intersPtAnPipe = ptsCol[0];
  52.                             }
  53.     
  54.                             // Найденная точка находится не на трубе,
  55.                             // поэтому, требуется ее уточнить                              
  56.     
  57.                             #region Один из вариантов уточнения координаты Z для точки
  58.     
  59.                             // 2D точка пересечения
  60.                             Point2d intersPt2D = new Point2d(intersPtAnPipe.X, intersPtAnPipe.Y);
  61.     
  62.                             // Начальная и конечная точки трубы
  63.                             Point3d
  64.                                 startPt = pipe.StartPoint,
  65.                                 endPt = pipe.EndPoint;
  66.     
  67.                             // Если 2D точка пересечения трубы и трассы находится в начале трубы
  68.                             if (intersPt2D.IsEqualTo(new Point2d(startPt.X, startPt.Y), Tolerance.Global))
  69.                                 // точка пересечения - начальная точка трубы
  70.                                 intersPtAnPipe = startPt;
  71.                             // Если 2D точка пересечения трубы и трассы находится в конце трубы
  72.                             if (intersPt2D.IsEqualTo(new Point2d(endPt.X, endPt.Y), Tolerance.Global))
  73.                                 // точка пересечения - конечная точка трубы
  74.                                 intersPtAnPipe = endPt;
  75.                             else
  76.                             {
  77.                                 // Математически определяем координату Z для точки
  78.                                 double
  79.                                     angleFactor = 0.0,
  80.                                     intersPtZ = 0.0;
  81.     
  82.                                 if (!intersPt2D.X.Equals(startPt.X))
  83.                                     angleFactor = (endPt.X - startPt.X) / (intersPt2D.X - startPt.X);
  84.     
  85.                                 else if (!intersPt2D.Y.Equals(startPt.Y))
  86.                                     angleFactor = (endPt.Y - startPt.Y) / (intersPt2D.Y - startPt.Y);
  87.     
  88.                                 intersPtZ = ((endPt.Z - startPt.Z) / angleFactor) + startPt.Z;
  89.     
  90.                                 intersPtAnPipe = new Point3d(intersPt2D.X, intersPt2D.Y, intersPtZ);
  91.                             }
  92.     
  93.                             #endregion
  94.                            
  95.                             // Ищем переопределение стиля трубы на виде профиля
  96.                             ProfileOverride pipeStyleOverride =
  97.                                 pView.GraphOverrides.SingleOrDefault(item =>
  98.                                     item.ProfileId.IsValid
  99.                                     && item.UseOverrideStyle
  100.                                     && item.ProfileId.Equals(pipe.ProfileViewPartId));
  101.     
  102.                             ObjectId pipeStyleId;
  103.     
  104.                             // Если стиль переопределен
  105.                             if (pipeStyleOverride != null)
  106.                             {
  107.                                 // Получаем Id стиля переопределения
  108.                                 pipeStyleId = pipeStyleOverride.OverrideStyleId;
  109.                             }
  110.                             else
  111.                             {
  112.                                 // Иначе - берем Id стиля трубы на плане
  113.                                 pipeStyleId = pipe.StyleId;
  114.                             }
  115.     
  116.                             // Получаем стиль трубы
  117.                             PipeStyle pipeStyle
  118.                                 = tr.GetObject(pipeStyleId, OpenMode.ForRead) as PipeStyle;
  119.     
  120.                             // Получаем настройки отображения элементов сечения
  121.                             // пересекающей трубы на виде профиля из стиля трубы
  122.     
  123.                             // Штриховка перескающей трубы
  124.                             DisplayStyle dispStyleCPH = pipeStyle.GetDisplayStyleProfile
  125.                                 (PipeDisplayStyleProfileType.CrossingPipeHatch);
  126.                             // Внутренняя стенка пересекающей трубы
  127.                             DisplayStyle dispStyleCPIW
  128.                                 = pipeStyle.GetDisplayStyleProfile
  129.                                 (PipeDisplayStyleProfileType.CrossingPipeInsideWall);
  130.                             // Внешняя стенка пересекающей трубы
  131.                             DisplayStyle dispStyleCPOW = pipeStyle.GetDisplayStyleProfile
  132.                                 (PipeDisplayStyleProfileType.CrossingPipeOutsideWall);
  133.     
  134.                             // Проверяем, показывается ли хоть один элемент сечения
  135.                             bool showCrossing
  136.                                 = dispStyleCPH.Visible
  137.                                 || dispStyleCPIW.Visible
  138.                                 || dispStyleCPOW.Visible;
  139.     
  140.                             // Если пересекающая труба никак не отображается - переходим
  141.                             // к следующему виду профиля
  142.                             if (!showCrossing) continue;
  143.     
  144.                             // Находим пикетаж точки пересечения трубы и вида профиля
  145.                             double station = 0.0, offset = 0.0;
  146.                             align.StationOffset
  147.                                 (intersPtAnPipe.X, intersPtAnPipe.Y, ref station, ref offset);
  148.     
  149.                             // Получаем координаты точки пересечения на виде профиля
  150.                             double x = 0.0, y = 0.0;
  151.                             pView.FindXYAtStationAndElevation
  152.                                 (station, intersPtAnPipe.Z, ref x, ref y);
  153.     
  154.                             // Получаем стиль вида профиля
  155.                             ProfileViewStyle pViewStyle
  156.                                 = tr.GetObject(pView.StyleId, OpenMode.ForRead) as ProfileViewStyle;
  157.     
  158.                             // Получаем вертикальный коэффициент масштабирования
  159.                             GraphStyle graphStyle = pViewStyle.GraphStyle;
  160.                             double verticalScaleFactor
  161.                                 = graphStyle.CurrentHorizontalScale / graphStyle.VerticalScale;
  162.     
  163.                             // Наружный радиус трубы по высоте в масштабе вида профиля
  164.                             double outerRadInScale
  165.                                 = pipe.OuterDiameterOrWidth * verticalScaleFactor / 2.0;
  166.     
  167.                             // Рисуем крестик на пересекающей трубе
  168.                             // pt1   pt3
  169.                             //    \ /
  170.                             //    / \
  171.                             // pt4   pt2
  172.     
  173.                             Point3d
  174.                                 pt1 = new Point3d
  175.                                     (x - outerRadInScale, y + outerRadInScale, pView.Location.Z),
  176.                                 pt2 = new Point3d
  177.                                     (x + outerRadInScale, y - outerRadInScale, pView.Location.Z),
  178.                                 pt3 = new Point3d
  179.                                     (x + outerRadInScale, y + outerRadInScale, pView.Location.Z),
  180.                                 pt4 = new Point3d
  181.                                     (x - outerRadInScale, y - outerRadInScale, pView.Location.Z);
  182.     
  183.                             wd.Geometry.WorldLine(pt1, pt2);
  184.                             wd.Geometry.WorldLine(pt3, pt4);
  185.                         }
  186.                     }
  187.     
  188.                     tr.Commit();
  189.                 }
  190.             }
  191.     
  192.             // если вам нужно обрабатывать колодцы
  193.             //else if (viewPart.ModelPartId.ObjectClass ==
  194.             //  RXClass.GetClass(typeof(Structure)))
  195.             //{
  196.             //}
  197.     
  198.             return ret;
  199.         }
  200.     }
  201.     
  202.     public class MyCommads
  203.     {
  204.         [CommandMethod("MyProfilePartOverrule")]
  205.         public static void CmdProfilePartOverrule()
  206.         {
  207.             if (_overrule == null)
  208.             {
  209.                 _overrule = new MyPipePartOverrule();
  210.                 Overrule.AddOverrule(
  211.                   RXClass.GetClass(typeof(ProfileViewPart)),
  212.                   _overrule, false);
  213.             }
  214.             else
  215.             {
  216.                 Overrule.RemoveOverrule(
  217.                   RXClass.GetClass(typeof(ProfileViewPart)),
  218.                   _overrule);
  219.                 _overrule = null;
  220.             }
  221.             Application.DocumentManager.
  222.               MdiActiveDocument.Editor.Regen();
  223.         }
  224.     
  225.         private static MyPipePartOverrule _overrule = null;
  226.     }

В результате, на видах профилей все пересекающие трубы будут с крестиками, как на рисунке:

 

PviewPartOver.dwg

Источник: http://adndevblog.typepad.com/infrastructure/2015/04/overrule-pipe-network-part-in-profile-view.html

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

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

Опубликовано 05.09.2015