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

28/04/2018

Использование фильтра пересечений для связанного файла

Вопрос: Я разрабатываю add-in, задача которого состоит в определении элементов модели, лежащих внутри формы, расположенной в связанном файле MassModel.rvt

Я использовал FilteredElementCollector c фильтром ElementIntersectsSolidFilter, используя геометрию моей формы в качестве аргумента.

Мой код:

Код - VB.NET: [Выделить]
  1. Public Sub Run()
  2.     Dim oWrite1 As IO.StreamWriter
  3.  
  4.     oWrite1 = IO.File.CreateText("C:/ . . . /ObjectLocation.txt")
  5.  
  6.     ' Получаем связанные файлы
  7.  
  8.     Dim linkedfilefilter As ElementCategoryFilter _
  9.         = New ElementCategoryFilter(BuiltInCategory.OST_RvtLinks)
  10.  
  11.     Dim linkedfilecollector As FilteredElementCollector _
  12.         = New FilteredElementCollector(m_doc) _
  13.             .WherePasses(linkedfilefilter) _
  14.             .WhereElementIsNotElementType
  15.  
  16.     Dim options As Options = New Options()
  17.  
  18.     Dim tx As Transaction = New Transaction(m_doc)
  19.     tx.Start("Object Locate")
  20.  
  21.     If linkedfilecollector.Count > 0 Then
  22.  
  23.         For Each linkedfile As RevitLinkInstance In linkedfilecollector
  24.  
  25.             If linkedfile.GetLinkDocument.Title.Equals("MassModel.rvt") Then
  26.                 Try
  27.  
  28.                     ' Получаем все элементы с параметром OBJ-LOCATION-RDK
  29.                     ' И очищаем значение параметра
  30.  
  31.                     Dim collector As FilteredElementCollector _
  32.                         = New FilteredElementCollector(m_doc) _
  33.                             .WhereElementIsNotElementType _
  34.                             .WhereElementIsViewIndependent
  35.  
  36.                     For Each el As Element In collector
  37.                         If el.Category IsNot Nothing And el.Parameters.Size > 0 Then
  38.                             Dim ElementParameters As ParameterSet = el.Parameters
  39.                             For Each elparam As Parameter In ElementParameters
  40.                                 If elparam.Definition.Name = "OBJ-LOCATION-RDK" Then
  41.                                     elparam.Set("")
  42.                                     oWrite1.WriteLine(el.Category.Name)
  43.                                 End If
  44.                             Next
  45.                         End If
  46.                     Next
  47.  
  48.                     Dim linkedmassCatFilter As ElementCategoryFilter _
  49.                         = New ElementCategoryFilter(BuiltInCategory.OST_Mass)
  50.  
  51.                     Dim massCollector As FilteredElementCollector _
  52.                         = New FilteredElementCollector(linkedfile.GetLinkDocument) _
  53.                             .WhereElementIsNotElementType() _
  54.                             .WherePasses(linkedmassCatFilter)
  55.  
  56.                     Dim populatedcounter As Integer = 0
  57.                     For Each mass As Element In massCollector
  58.                         Dim solSet As Generic.IEnumerable(Of Solid) _
  59.                             = mass.Geometry(options).OfType(Of Solid)()
  60.  
  61.                         For Each potSol As Solid In solSet
  62.                             If (potSol IsNot Nothing And Not potSol.Edges.IsEmpty) Then
  63.  
  64.                                 Dim elementintersectsolidfilter As ElementIntersectsSolidFilter _
  65.                                     = New ElementIntersectsSolidFilter(potSol)
  66.  
  67.                                 Dim intersectingelems As FilteredElementCollector _
  68.                                     = New FilteredElementCollector(m_doc) _
  69.                                         .WherePasses(elementintersectsolidfilter)
  70.  
  71.                                 oWrite1.WriteLine("intersecting elems: " _
  72.                                     + intersectingelems.Count.ToString)
  73.  
  74.                                 For Each intersectingelem As Element In intersectingelems
  75.                                     Dim ElementParameters As ParameterSet _
  76.                                         = intersectingelem.Parameters
  77.  
  78.                                     For Each param As Parameter In ElementParameters
  79.                                         If param.Definition.Name = "OBJ-LOCATION-RDK" Then
  80.                                             If Not param.AsString = "" Then
  81.                                                 param.Set(param.AsString + "+" + mass.Name)
  82.                                             Else
  83.                                                 param.Set(mass.Name)
  84.                                                 populatedcounter += 1
  85.                                             End If
  86.                                         End If
  87.                                     Next
  88.                                 Next
  89.                             End If
  90.                         Next
  91.                     Next
  92.                     MsgBox("Populated parameter OBJ-LOCATION-RDK for " _
  93.                                  + populatedcounter.ToString + " model elements")
  94.                     Exit For
  95.  
  96.  
  97.                 Catch ex As Exception
  98.                 End Try
  99.  
  100.             Else
  101.                 MsgBox("Не найдены связанные файлы MassModel.rvt")
  102.             End If
  103.         Next
  104.  
  105.     Else
  106.         MsgBox("Не найдено связанных файлов. " _
  107.                      + "Вставьте связанный файл MassModel.rvt в проект")
  108.     End If
  109.  
  110.     tx.Commit()
  111.  
  112.     oWrite1.Close()
  113. End Sub


Мне непонятно, почему он возвращает элементы, которые были смещены или отсоединены от их рабочей плоскости.

Есть ли более простой способ, например как нод Dynamo "geometry.DoesIntersect"?

Ответ: Для начала пара комментариев к Вашему коду.

Во-первых, проще и безопаснее инкапсулировать транзакции в using. Посмотрите так же темы в разделе http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.53

Во-вторых, Вы можете получить параметр элемента по имени. Вообще говоря, еще лучше, получать параметры так, чтобы не зависеть от отображаемого имени (примечание переводчика: с помощью перечисления BuiltInParameter или GUID-а общего параметра), но оно будет прекрасно работать и так, если Вы уверены, что имя параметра уникально для данного элемента.
Соответственно, Вы можете заменить код:
Код - VB.NET: [Выделить]
  1.  For Each elparam As Parameter In ElementParameters
  2.     If elparam.Definition.Name = "OBJ-LOCATION-RDK" Then
  3.       elparam.Set("")
  4.       oWrite1.WriteLine(el.Category.Name)
  5.     End If
  6. Next


На:
Код - C#: [Выделить]
  1.  IList plist = e.GetParameters("OBJ-LOCATION-RDK")
  2. Parameter elparam = plist[0]
  3. elparam.Set("")



Примечаниепереводчика: есть еще метод LookupParameter, можно еще упростить код:
Код - C#: [Выделить]
  1.  e.LookupParameter("OBJ-LOCATION-RDK")?.Set("");


Этот код быстрее, эффективнее, его проще прочитать и понять.

Теперь ближе к теме Вашего вопроса. Форма расположена в linkedfile.GetLinkDocument и Вы получаете potSol из неё, правильно? В то время как элементы, пересечение которых с формой Вы пытаетесь найти, содержатся в m_doc. А Вы учли преобразование координат между связанным фалом и основным проектом?

Мы недавно обсуждали получение пересекающихся элементов в общем и поиск пересечения твердотельной геометрии в связанном файле

Поэтому я предлагаю следующее:
У Васть есть два элемента с твердотельной геометрией, A в основном документе P и B в связанном файле Q.
- определите преобразование координат T от связанного файла Q к координатам документа P
- откройте связанный файл Q и получите геометрию Sb элемента B
- преобразуйте его в пространство координат документа P: T*Sb
- получите геометрию Sa элемента А
- получите геометрию пересечения T*Sb и Sa

Теперь Вы можете использовать ElementIntersectsSolidFilter, используя полученную геометрию.

Преобразование Sb Вы можете получить, используя метод SolidUtils.CreateTransformed

Примечание переводчика: можно использовать метод GeometryElement.GetTransformed, т.е. что-то вроде:
Код - C#: [Выделить]
  1.  element.get_Geometry(new Options()).GetTransformed(transform)


Ответ: Да, Вы правы, я не учел преобразование координат формы из связанного файла. И только благодаря "удаче" каждый раз я получал смещенные и отсоединенные элементы. Теперь всё работает как и ожидается:
Код - VB.NET: [Выделить]
  1.  ' Определяем преобразование координат между связанным и основным файлами
  2.  
  3. Dim transform As Transform = linkedfile.GetTotalTransform
  4.  
  5. For Each mass As Element In massCollector
  6.  
  7.     Dim massSolids As Generic.IEnumerable(Of Solid) _
  8.         = mass.Geometry(options).OfType(Of Solid)()
  9.  
  10.     For Each massSolid As Solid In massSolids
  11.  
  12.         If (massSolid IsNot Nothing _
  13.             And Not massSolid.Edges.IsEmpty) Then
  14.  
  15.             ' Применяем геометрическое преобразование
  16.  
  17.             Dim transformedSolid As Solid = SolidUtils _
  18.                 .CreateTransformed(massSolid, transform)
  19.  
  20.             Dim elementIntersectsSolidFilter As _
  21.                 ElementIntersectsSolidFilter = New _
  22.                  ElementIntersectsSolidFilter(transformedSolid)
  23.  
  24.             Dim intersectingElems As FilteredElementCollector _
  25.                 = New FilteredElementCollector(m_doc) _
  26.                     .WhereElementIsNotElementType _
  27.                     .WhereElementIsViewIndependent _
  28.                     .WherePasses(elementIntersectsSolidFilter)
  29.  
  30.             For Each intersectingElem As Element _
  31.                 In intersectingElems
  32.  
  33.                 Dim elParams As IList(Of Parameter) _
  34.                     = intersectingElem.GetParameters(
  35.                         "Mass Intersections")
  36.  
  37.                 If elParams.Count > 0 Then
  38.                     Dim elParam As Parameter = elParams(0)
  39.                     If elParam.AsString = "" Then
  40.                         elParam.Set(mass.Name)
  41.                         populatedCounter += 1
  42.                     Else
  43.                         elParam.Set(elParam.AsString _
  44.                                                 + "+" + mass.Name)
  45.                     End If
  46.                 End If
  47.             Next
  48.  
  49.         End If
  50.     Next
  51. Next


Источник: http://thebuildingcoder.typepad.com/blog/2018/04/using-intersection-filter-with-linked-file.html

 

Автор перевода: Александр Игнатович

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

Опубликовано 28.04.2018
Отредактировано 28.04.2018 в 13:27:41