28/04/2018
Использование фильтра пересечений для связанного файла
Вопрос: Я разрабатываю add-in, задача которого состоит в определении элементов модели, лежащих внутри формы, расположенной в связанном файле MassModel.rvt
Я использовал FilteredElementCollector c фильтром ElementIntersectsSolidFilter, используя геометрию моей формы в качестве аргумента.
Мой код:
Код - VB.NET: [Выделить]
- Public Sub Run()
- Dim oWrite1 As IO.StreamWriter
- oWrite1 = IO.File.CreateText("C:/ . . . /ObjectLocation.txt")
- ' Получаем связанные файлы
- Dim linkedfilefilter As ElementCategoryFilter _
- = New ElementCategoryFilter(BuiltInCategory.OST_RvtLinks)
- Dim linkedfilecollector As FilteredElementCollector _
- = New FilteredElementCollector(m_doc) _
- .WherePasses(linkedfilefilter) _
- .WhereElementIsNotElementType
- Dim options As Options = New Options()
- Dim tx As Transaction = New Transaction(m_doc)
- tx.Start("Object Locate")
- If linkedfilecollector.Count > 0 Then
- For Each linkedfile As RevitLinkInstance In linkedfilecollector
- If linkedfile.GetLinkDocument.Title.Equals("MassModel.rvt") Then
- Try
- ' Получаем все элементы с параметром OBJ-LOCATION-RDK
- ' И очищаем значение параметра
- Dim collector As FilteredElementCollector _
- = New FilteredElementCollector(m_doc) _
- .WhereElementIsNotElementType _
- .WhereElementIsViewIndependent
- For Each el As Element In collector
- If el.Category IsNot Nothing And el.Parameters.Size > 0 Then
- Dim ElementParameters As ParameterSet = el.Parameters
- For Each elparam As Parameter In ElementParameters
- If elparam.Definition.Name = "OBJ-LOCATION-RDK" Then
- elparam.Set("")
- oWrite1.WriteLine(el.Category.Name)
- End If
- Next
- End If
- Next
- Dim linkedmassCatFilter As ElementCategoryFilter _
- = New ElementCategoryFilter(BuiltInCategory.OST_Mass)
- Dim massCollector As FilteredElementCollector _
- = New FilteredElementCollector(linkedfile.GetLinkDocument) _
- .WhereElementIsNotElementType() _
- .WherePasses(linkedmassCatFilter)
- Dim populatedcounter As Integer = 0
- For Each mass As Element In massCollector
- Dim solSet As Generic.IEnumerable(Of Solid) _
- = mass.Geometry(options).OfType(Of Solid)()
- For Each potSol As Solid In solSet
- If (potSol IsNot Nothing And Not potSol.Edges.IsEmpty) Then
- Dim elementintersectsolidfilter As ElementIntersectsSolidFilter _
- = New ElementIntersectsSolidFilter(potSol)
- Dim intersectingelems As FilteredElementCollector _
- = New FilteredElementCollector(m_doc) _
- .WherePasses(elementintersectsolidfilter)
- oWrite1.WriteLine("intersecting elems: " _
- + intersectingelems.Count.ToString)
- For Each intersectingelem As Element In intersectingelems
- Dim ElementParameters As ParameterSet _
- = intersectingelem.Parameters
- For Each param As Parameter In ElementParameters
- If param.Definition.Name = "OBJ-LOCATION-RDK" Then
- If Not param.AsString = "" Then
- param.Set(param.AsString + "+" + mass.Name)
- Else
- param.Set(mass.Name)
- populatedcounter += 1
- End If
- End If
- Next
- Next
- End If
- Next
- Next
- + populatedcounter.ToString + " model elements")
- Exit For
- Catch ex As Exception
- End Try
- Else
- End If
- Next
- Else
- + "Вставьте связанный файл MassModel.rvt в проект")
- End If
- tx.Commit()
- End Sub
Мне непонятно, почему он возвращает элементы, которые были смещены или отсоединены от их рабочей плоскости.
Есть ли более простой способ, например как нод Dynamo "geometry.DoesIntersect"?
Ответ: Для начала пара комментариев к Вашему коду.
Во-первых, проще и безопаснее инкапсулировать транзакции в using. Посмотрите так же темы в разделе http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.53
Во-вторых, Вы можете получить параметр элемента по имени. Вообще говоря, еще лучше, получать параметры так, чтобы не зависеть от отображаемого имени (примечание переводчика: с помощью перечисления BuiltInParameter или GUID-а общего параметра), но оно будет прекрасно работать и так, если Вы уверены, что имя параметра уникально для данного элемента.
Соответственно, Вы можете заменить код:
Код - VB.NET: [Выделить]
- For Each elparam As Parameter In ElementParameters
- If elparam.Definition.Name = "OBJ-LOCATION-RDK" Then
- elparam.Set("")
- oWrite1.WriteLine(el.Category.Name)
- End If
- Next
На:
Код - C#: [Выделить]
- IList plist = e.GetParameters("OBJ-LOCATION-RDK")
- Parameter elparam = plist[0]
- elparam.Set("")
Примечаниепереводчика: есть еще метод LookupParameter, можно еще упростить код:
Код - C#: [Выделить]
- 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#: [Выделить]
- element.get_Geometry(new Options()).GetTransformed(transform)
Ответ: Да, Вы правы, я не учел преобразование координат формы из связанного файла. И только благодаря "удаче" каждый раз я получал смещенные и отсоединенные элементы. Теперь всё работает как и ожидается:
Код - VB.NET: [Выделить]
- ' Определяем преобразование координат между связанным и основным файлами
- Dim transform As Transform = linkedfile.GetTotalTransform
- For Each mass As Element In massCollector
- Dim massSolids As Generic.IEnumerable(Of Solid) _
- = mass.Geometry(options).OfType(Of Solid)()
- For Each massSolid As Solid In massSolids
- If (massSolid IsNot Nothing _
- And Not massSolid.Edges.IsEmpty) Then
- ' Применяем геометрическое преобразование
- Dim transformedSolid As Solid = SolidUtils _
- .CreateTransformed(massSolid, transform)
- Dim elementIntersectsSolidFilter As _
- ElementIntersectsSolidFilter = New _
- ElementIntersectsSolidFilter(transformedSolid)
- Dim intersectingElems As FilteredElementCollector _
- = New FilteredElementCollector(m_doc) _
- .WhereElementIsNotElementType _
- .WhereElementIsViewIndependent _
- .WherePasses(elementIntersectsSolidFilter)
- For Each intersectingElem As Element _
- In intersectingElems
- Dim elParams As IList(Of Parameter) _
- = intersectingElem.GetParameters(
- "Mass Intersections")
- If elParams.Count > 0 Then
- Dim elParam As Parameter = elParams(0)
- If elParam.AsString = "" Then
- elParam.Set(mass.Name)
- populatedCounter += 1
- Else
- elParam.Set(elParam.AsString _
- + "+" + mass.Name)
- End If
- End If
- Next
- End If
- Next
- Next
Источник: http://thebuildingcoder.typepad.com/blog/2018/04/using-intersection-filter-with-linked-file.html
Автор перевода: Александр Игнатович
Отредактировано 28.04.2018 в 13:27:41
Обсуждение: http://adn-cis.org/forum/index.php?topic=
Опубликовано 28.04.2018Отредактировано 28.04.2018 в 13:27:41