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

27/02/2014

Список элементов инженерной системы

Инженерная система в Revit API описывается классом MEPSystem.

Для того чтобы получить список всех элементов, входящих в систему, достаточно воспользоваться свойством MEPSystem.Elements.

Но, как оказалось, это свойство не всегда возвращает полный список элементов, принадлежащих системе.

Для примера я создал простой проект, куда поместил одну Установку с переменным объемом воздуха и создал несколько воздуховодов с фитингами.

 

Все элементы входят в одну систему. Если мы выделим любой из этих элементов, то видим, что свойство Имя системы у всех элементов одинаковое – Механизмы Приточный воздух 1.

 

Выполним следующий код, чтобы проверить что же нам вернет свойство MEPSystem.Elements.

Код - C#: [Выделить]
  1.             var filteredElementCollector = new FilteredElementCollector(doc);
  2.             var systems =
  3.                 filteredElementCollector
  4.                     .OfClass(typeof (MEPSystem))
  5.                     .ToElements();
  6.  
  7.             StringBuilder sb = new StringBuilder();
  8.  
  9.             foreach (MEPSystem system in systems)
  10.             {               
  11.                 sb.AppendLine(string.Format("{0}: {1} Type: {2}; Количество элементов: {3}",
  12.                     system.Id,
  13.                     system.Name,
  14.                     system.GetType().Name,
  15.                     system.Elements.OfType<Element>().Count()));
  16.  
  17.                 foreach (Element element in system.Elements)
  18.                 {
  19.                     sb.AppendLine(string.Format("    {0}: {1} Тип: {2}",
  20.                     element.Id,
  21.                     element.Name,
  22.                     element.GetType().Name));
  23.                 }
  24.  
  25.             }
  26.  
  27.             TaskDialog.Show("Systems", sb.ToString());

В сообщении видим

 

Таким образом, с помощью свойства Elements, мы получили только два(!!!) элемента.

Я уже отметил ранее, что у всех элементов свойство Имя системы одинаковое. Таким образом, чтобы получить полный список элементов, принадлежащих системе, нужно выбрать все элементы, у которых значение параметра Имя системы равно наименованию выбранной системы.

В этом нам как всегда поможет FilteredElementCollector.

Искать нам нужно по значению параметра, поэтому будем применять ElementParameterFilter. Важно помнить, что фильтр принадлежит к классу так называемых «медленных» фильтров, поэтому без острой необходимости его применять не следует, либо предварительно ограничить выборку «быстрыми» фильтрами.

Я бы предпочел искать по идентификатору системы, так как это более надежно, и возможно чуточку быстрее. Но, к сожалению, элемент содержит только наименование системы. Что ж, учитывая, что наименование системы уникально в одном проекте, то вариант поиска по наименованию тоже не плох.

Наименование системы хранится во встроенном параметре RBS_SYSTEM_NAME_PARAM.

От теории перейдем к практике. Так как я мне нравится возможность .NET, как методы расширения (естественно там, где они уместны), воспользуемся ей и создадим вот такой метод:

Код - C#: [Выделить]
  1.     public static class MEPSystemExtensions
  2.     {
  3.         public static IEnumerable<Element> GetElements(this MEPSystem system)
  4.         {
  5.             var collector = new FilteredElementCollector(system.Document);
  6.  
  7.             FilterableValueProvider valueProvider =
  8.                 new ParameterValueProvider(new ElementId(BuiltInParameter.RBS_SYSTEM_NAME_PARAM));
  9.  
  10.             FilterRule filterRule =
  11.                 new FilterStringRule(valueProvider, new FilterStringEquals(), system.Name, true);
  12.  
  13.             ElementParameterFilter systemNameParameterFilter =
  14.                 new ElementParameterFilter(filterRule);
  15.  
  16.             ElementClassFilter familyInstanceClassFilter =
  17.                 new ElementClassFilter(typeof (FamilyInstance));
  18.             ElementClassFilter mepCurveClassFilter =
  19.                 new ElementClassFilter(typeof(MEPCurve));
  20.  
  21.             ElementLogicalFilter bothClassFilter =
  22.                 new LogicalOrFilter(familyInstanceClassFilter, mepCurveClassFilter);
  23.  
  24.             var elements =
  25.                 collector
  26.                     .WhereElementIsNotElementType()
  27.                     .WherePasses(bothClassFilter)                   
  28.                     .WherePasses(systemNameParameterFilter);
  29.  
  30.             return elements;
  31.         }
  32.     }  

Немного пояснений:

  • Последний параметр в конструкторе класса FilterStringRule указывает учитывать ли регистр или нет. Так как наименование системы в проекте уникально, но чувствительно к регистру, то нужно обязательно указать параметр равным true.
  • Первоначально я не делал фильтрацию по классу, но в этом случае в выборку попадают лишние элементы, такие как осевые линии
  • В систему могут входить только экземпляры семейства и объекты класса MEPCurve: трубы, воздуховоды, кабельные лотки и т.п.

Теперь, если вместо свойства MEPSystem.Elements воспользоваться методом MEPSystem.GetElements(), то получим уже более правильный результат:

 

В результате, видим все объекты, принадлежащие системе.

Автор: Виктор Чекалин
Автор перевода: Виктор Чекалин

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

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