Фильтр по материалам

Автор Тема: Фильтр по материалам  (Прочитано 7978 раз)

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

Оффлайн AlexanderАвтор темы

  • ADN OPEN
  • Сообщений: 27
  • Карма: 0
Фильтр по материалам
« : 13-02-2014, 15:33:04 »
Добрый день!

В проекте есть несколько перекрытий(полы), которые состоят из нескольких материалов(например бетон, плитка и т.д.). Мне нужно отфильтровать эти материалы, чтобы получить их описание и записать в общий параметр, который является параметром перекрытие.
Поскольку в проекте несколько уровней, фильтр должен быть ещё и по уровням.  То есть сначала фильтр по уровням, потом по перекрытиям и по материалам.
Создать фильтр для материалов по уровням или для перекрытий по уровням у меня получилось, но всё вместе пока не получается.
Возможен ли такой фильтр?

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Re: Фильтр по материалам
« Ответ #1 : 13-02-2014, 16:17:28 »
Добрый день.

Речь идет о создании фильтра в спецификации?

Оффлайн AlexanderАвтор темы

  • ADN OPEN
  • Сообщений: 27
  • Карма: 0
Re: Фильтр по материалам
« Ответ #2 : 13-02-2014, 16:21:55 »
Нет

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Re: Фильтр по материалам
« Ответ #3 : 13-02-2014, 16:25:09 »
А о каком? FilteredElementCollector?

Так как вы написали, что у вас получилось сделать фильтр по отдельности, а вместе - нет, то неплохо было бы привести пример кода, дабы посмотреть что там не верно.

Оффлайн AlexanderАвтор темы

  • ADN OPEN
  • Сообщений: 27
  • Карма: 0
Re: Фильтр по материалам
« Ответ #4 : 13-02-2014, 16:44:39 »
           
Код - C# [Выбрать]
  1.         public static ElementId FindLevelId(Document doc, string name)
  2.         {
  3.             FilteredElementCollector collectorLevels = new FilteredElementCollector(doc);
  4.             collectorLevels.OfClass(typeof(Level));
  5.  
  6.             // Now use LINQ to see if one exists with provided name.
  7.             ElementId idLevel = ElementId.InvalidElementId;
  8.             try
  9.             {
  10.                 Element levelMatched = collectorLevels.First(level => level.Name.Equals(name));
  11.                 if (levelMatched != null)
  12.                     idLevel = levelMatched.Id;
  13.             }
  14.             catch (System.InvalidOperationException)
  15.             {
  16.             }
  17.             catch (System.ArgumentNullException)
  18.             {
  19.             }
  20.             return idLevel;
  21.         }
  22.  
  23.             ElementId levelFirstId = FindLevelId(activeDoc, level_first);
  24.             ElementLevelFilter filterElementsOnLevelOne = new ElementLevelFilter(levelFirstId);
  25.             FilteredElementCollector filteredElementCollectorWallOne = new FilteredElementCollector(activeDoc);
  26.             var LevelOneParam = filteredElementCollectorWallOne.OfClass(typeof(Floor));
  27.             LevelOneParam.OfCategory(BuiltInCategory.OST_Floors);
  28.             LevelOneParam.WherePasses(filterElementsOnLevelOne);
  29.  
  30.             foreach (Floor floor in LevelOneParam)
  31.             {
  32.                 Parameter parameterDescription = floor.get_Parameter("Описание1");
  33.                 Parameter parameterMatName = floor.get_Parameter(BuiltInParameter.MATERIAL_NAME);            
  34.                 var text = parameterMatName.AsString();
  35.                 var res = floor.get_Parameter("Описание1").Set(" слово ");
  36.             }

В таком случае он не найдёт parameterMatName , но в общий параметр Описание1 можно записать символы.
Вопрос в том, как создать фильтр, чтобы ещё и parameterMatName был виден.

Фильтр для материалов:
Код - C# [Выбрать]
  1.         ElementId levelFirstId = FindLevelId(activeDoc, _level_first);
  2.             FilteredElementCollector collector1 = new FilteredElementCollector(activeDoc);
  3.             BuiltInParameter bip = BuiltInParameter.FAMILY_LEVEL_PARAM;
  4.             ParameterValueProvider provider = new ParameterValueProvider(new ElementId(bip));
  5.             FilterNumericRuleEvaluator evaluator = new FilterNumericEquals();
  6.             FilterRule ruleOne = new FilterElementIdRule(provider, evaluator, levelFirstId);
  7.             ElementParameterFilter filterOne = new ElementParameterFilter(ruleOne);
  8.             collector1.OfClass(typeof(Material)).OfType<Material>();
  9.             //collector1.OfCategory(BuiltInCategory.OST_Materials);
  10.             //collector1.WherePasses(filterOne);
  11.             ICollection<Element> LevelOneParam = collector1.ToElements();
  12.            
  13.             foreach (Materials materials in LevelOneParam)
  14.             {
  15.                 Parameter parameterDescription = materials.get_Parameter("Описание1");
  16.                 Parameter parameterMatName = materials.get_Parameter(BuiltInParameter.MATERIAL_NAME);            
  17.                 var text = parameterMatName.AsString();
  18.                 var res = materials.get_Parameter("Описание1").Set(" слово ");
  19.             }
« Последнее редактирование: 14-02-2014, 08:26:32 от Виктор Чекалин »

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Re: Фильтр по материалам
« Ответ #5 : 14-02-2014, 09:26:10 »
Александр, добрый день.

Скажу честно, что можно сказать я совсем не понял что вы хотите сделать и что делает код, так как он в большей части бессмысленный.

Для начала я попробую перефразировать вашу задачу своими словами, чтобы убедиться правильно ли я понял вашу мысль или нет.

Да, и параметр "Описание1" - это общий параметр для Материала или для Перекрытия?

Задача как ее понял я.
У меня два варианта:
1) Нужно выбрать все перекрытия на определенном уровне, затем получить список материалов, из которых сделаны эти перекрытия и записать список всех материалов в общий параметр перекрытия (не ясно только для чего).
2) Для каждого перекрытия находящегося на определенном уровне нужно записать в общий параметр описание материала из которого сделано это перекрытие (более вероятный сценарий)

Тем не менее есть много замечаний к коду, да и вообще к логике работы.

В начале темы вы пишите:
Создать фильтр для материалов по уровням <...> у меня получилось, но всё вместе пока не получается.

Затем приводите код:
Код - C# [Выбрать]
  1. FilteredElementCollector collector1 = new FilteredElementCollector(activeDoc);
  2. ElementParameterFilter filterOne = new ElementParameterFilter(ruleOne);
  3. collector1.OfClass(typeof(Material)).OfType<Material>();
  4. //collector1.OfCategory(BuiltInCategory.OST_Materials);
  5. //collector1.WherePasses(filterOne);
  6. ICollection<Element> LevelOneParam = collector1.ToElements();
  7.  

Однако этот фильтр выберет просто все материалы в проекте. То что у вас закомментировано, где вы видимо хотели отфильтровать материалы, находящиеся на определенном уровне, естественно работать не будет. Во-первых, у материала нет параметра FAMILY_LEVEL_PARAM, во-вторых, логически такой подход не верен.
Материал - это некоторая сущность, которая характеризует свойство элемента. Таким образом, в принципе нельзя получить свойство, находящееся на таком то уровне. На уровне элементы находятся.

Затем, что в первом куске кода, что во-втором, идет несвязанный друг с другом код:
Код - C# [Выбрать]
  1.                 Parameter parameterDescription = floor.get_Parameter("Описание1");
  2.                 Parameter parameterMatName = floor.get_Parameter(BuiltInParameter.MATERIAL_NAME);            
  3.                 var text = parameterMatName.AsString();
  4.                 var res = floor.get_Parameter("Описание1").Set(" слово ");

Вы записываете в параметр "Описание1" некое значение, которое никак не зависит от трех предыдущих строчек. Причем те 3 строчки не несут совсем никакой нагрузки.

В таком случае он не найдёт parameterMatName , но в общий параметр Описание1 можно записать символы.
Вопрос в том, как создать фильтр, чтобы ещё и parameterMatName был виден.
\

Как я уже сказал, естественно в общий параметр Описание1 можно записать символы, так как дополнительной проверки у вас нет.
parameterMatName не будет не виден никогда. У перекрытия нет и не было такого параметра. Это параметр Материала.

В то же время, перекрытие может состоять из нескольких материалов. Но структурный материал у перекрытия всегда один. Его можно получить с помощью встроенного параметра STRUCTURAL_MATERIAL_PARAM. Правда он тоже может быть равен ElementId.InvalidElementId если материал задан по категории. В этому случае нужно получить материал из категории.

Александр, в общем постарайтесь сформулировать вашу задачу с описанием того, какой должен быть итог, либо подтвердите мои предположения. Изначально вопрос про фильтр стоит неверно, так как судя по всему, тут не в фильтре дело совсем.

Оффлайн AlexanderАвтор темы

  • ADN OPEN
  • Сообщений: 27
  • Карма: 0
Re: Фильтр по материалам
« Ответ #6 : 17-02-2014, 09:45:47 »
Виктор, спасибо за ответ.
Я хочу создать объединённую таблицу(на фото). Таблица состоит из спецификации перекрытий и ведомости материалов для перекрытий(в таблице это Данные элементов пола).
Тип этой таблицы так же спецификация.
Данные элементов пола - это поле Материал: Описание из ведомости материалов.

Поэтому я хочу создать текстовый общий параметр Описание1(для каждого перекрытия) и записать в него описание материала. В дальнейшем вставить его в спецификацию.



Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Re: Фильтр по материалам
« Ответ #7 : 17-02-2014, 17:16:39 »
Добрый день.

В таком случае вам надо выбрать все перекрытия на определенном уровне (вы это уже сделали).
Затем, перебирая в цикле все перекрытия, для каждого перекрытия определяете материал. Получаете описание материала и записываете значение в параметр перекрытия.

Код будет примерно такой:

Код - C# [Выбрать]
  1.             ElementId levelFirstId = FindLevelId(activeDoc, level_first);
  2.             ElementLevelFilter filterElementsOnLevelOne = new ElementLevelFilter(levelFirstId);
  3.             FilteredElementCollector filteredElementCollectorWallOne = new FilteredElementCollector(activeDoc);
  4.             var LevelOneParam = filteredElementCollectorWallOne.OfClass(typeof(Floor));
  5.             LevelOneParam.OfCategory(BuiltInCategory.OST_Floors);
  6.             LevelOneParam.WherePasses(filterElementsOnLevelOne);
  7.  
  8.             foreach (Floor floor in LevelOneParam)
  9.             {
  10.                 //Находим материал
  11.                 var floorType = doc.GetElement(floor.GetTypeId()) as FloorType;
  12.  
  13.                 // Получаем структурный материал
  14.  
  15.                 var materialId = floorType.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM);        
  16.                 //Если материал определен по категории, то определяем его
  17.                 if (materialId == ElementId.InvalidElementId)
  18.                 {
  19.                       materialId = floorType.Category.Material.Id;
  20.                  }
  21.  
  22.                 Material material = doc.GetElement(materialId) as Material;
  23.  
  24.                 //описание материала
  25.                 var materialDescription = material.get_Parameter("Описание1").AsString();          
  26.  
  27.                 var res = floor.get_Parameter("Описание1").Set(materialDescription );
  28.             }

Код я не проверял, но думаю смысл понятен.

Еще логичнее было бы записывать описание материала не в параметр конкретного перекрытия, а в параметр типа перекрытия, так как материал задается именно для типа.

Оффлайн AlexanderАвтор темы

  • ADN OPEN
  • Сообщений: 27
  • Карма: 0
Re: Фильтр по материалам
« Ответ #8 : 18-02-2014, 09:39:52 »
Спасибо.
Ещё один вопрос:
Через API у нас есть доступ к общим параметрам созданным пользователем в ревите. Возможно ли программно работать с параметрами проекта, которые создал пользователь?

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Re: Фильтр по материалам
« Ответ #9 : 18-02-2014, 10:31:02 »
Доступ к параметрам проекта (не общим) через API ограничен. Можно получить список всех параметров (общих и не общих) и получить доступ к привязанным категориям. Но понять какой параметр общий, а какой нет - нельзя.
Фактически получается единственное, что можно сделать через API - поменять привязку параметра к категории, зная его наименование. Возможно еще удалить параметр. А вот добавить новый - не выйдет.

Подробней про доступ к параметрам я писал в статье: http://adn-cis.org/dostup-k-opredeleniyam-obshhix-parametrov-proekta.html