Список элементов инженерной системы
Инженерная система в Revit API описывается классом MEPSystem.Для того чтобы получить список всех элементов, входящих в систему, достаточно воспользоваться свойством MEPSystem.Elements.
Но, как оказалось, это свойство не всегда возвращает полный список элементов, принадлежащих системе.
Для примера я создал простой проект, куда поместил одну Установку с переменным объемом воздуха и создал несколько воздуховодов с фитингами.
Все элементы входят в одну систему. Если мы выделим любой из этих элементов, то видим, что свойство Имя системы у всех элементов одинаковое – Механизмы Приточный воздух 1.
Выполним следующий код, чтобы проверить что же нам вернет свойство MEPSystem.Elements.
- var filteredElementCollector = new FilteredElementCollector(doc);
- var systems =
- filteredElementCollector
- .OfClass(typeof (MEPSystem))
- .ToElements();
- StringBuilder sb = new StringBuilder();
- foreach (MEPSystem system in systems)
- {
- sb.AppendLine(string.Format("{0}: {1} Type: {2}; Количество элементов: {3}",
- system.Id,
- system.Name,
- system.GetType().Name,
- system.Elements.OfType<Element>().Count()));
- foreach (Element element in system.Elements)
- {
- sb.AppendLine(string.Format(" {0}: {1} Тип: {2}",
- element.Id,
- element.Name,
- element.GetType().Name));
- }
- }
- TaskDialog.Show("Systems", sb.ToString());
В сообщении видим
Таким образом, с помощью свойства Elements, мы получили только два(!!!) элемента.
Я уже отметил ранее, что у всех элементов свойство Имя системы одинаковое. Таким образом, чтобы получить полный список элементов, принадлежащих системе, нужно выбрать все элементы, у которых значение параметра Имя системы равно наименованию выбранной системы.
В этом нам как всегда поможет FilteredElementCollector.
Искать нам нужно по значению параметра, поэтому будем применять ElementParameterFilter. Важно помнить, что фильтр принадлежит к классу так называемых «медленных» фильтров, поэтому без острой необходимости его применять не следует, либо предварительно ограничить выборку «быстрыми» фильтрами.
Я бы предпочел искать по идентификатору системы, так как это более надежно, и возможно чуточку быстрее. Но, к сожалению, элемент содержит только наименование системы. Что ж, учитывая, что наименование системы уникально в одном проекте, то вариант поиска по наименованию тоже не плох.
Наименование системы хранится во встроенном параметре RBS_SYSTEM_NAME_PARAM.
От теории перейдем к практике. Так как я мне нравится возможность .NET, как методы расширения (естественно там, где они уместны), воспользуемся ей и создадим вот такой метод:
- public static class MEPSystemExtensions
- {
- public static IEnumerable<Element> GetElements(this MEPSystem system)
- {
- var collector = new FilteredElementCollector(system.Document);
- FilterableValueProvider valueProvider =
- new ParameterValueProvider(new ElementId(BuiltInParameter.RBS_SYSTEM_NAME_PARAM));
- FilterRule filterRule =
- new FilterStringRule(valueProvider, new FilterStringEquals(), system.Name, true);
- ElementParameterFilter systemNameParameterFilter =
- new ElementParameterFilter(filterRule);
- ElementClassFilter familyInstanceClassFilter =
- new ElementClassFilter(typeof (FamilyInstance));
- ElementClassFilter mepCurveClassFilter =
- new ElementClassFilter(typeof(MEPCurve));
- ElementLogicalFilter bothClassFilter =
- new LogicalOrFilter(familyInstanceClassFilter, mepCurveClassFilter);
- var elements =
- collector
- .WhereElementIsNotElementType()
- .WherePasses(bothClassFilter)
- .WherePasses(systemNameParameterFilter);
- return elements;
- }
- }
Немного пояснений:
- Последний параметр в конструкторе класса FilterStringRule указывает учитывать ли регистр или нет. Так как наименование системы в проекте уникально, но чувствительно к регистру, то нужно обязательно указать параметр равным true.
- Первоначально я не делал фильтрацию по классу, но в этом случае в выборку попадают лишние элементы, такие как осевые линии
- В систему могут входить только экземпляры семейства и объекты класса MEPCurve: трубы, воздуховоды, кабельные лотки и т.п.
Теперь, если вместо свойства MEPSystem.Elements воспользоваться методом MEPSystem.GetElements(), то получим уже более правильный результат:
В результате, видим все объекты, принадлежащие системе.
Автор перевода: Виктор Чекалин
Обсуждение: http://adn-cis.org/forum/index.php?topic=576
Опубликовано 27.02.2014