FilteredElementCollector (doc, _view.Id) if _view create via view.Duplicate

Автор Тема: FilteredElementCollector (doc, _view.Id) if _view create via view.Duplicate  (Прочитано 8186 раз)

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

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Приветствую!!!
Пытался найти информацию о том, как во время выполнения скрипта в динамо, использовать FilteredElementCollector(doc, newId) где newId = view.Duplicate(ViewDuplicateOption.WithDetailing). Находил темы, где писали, что это пока не реализовано...
Задача такая: я создаю копию вида (в моём случае это FloorPlan), затем применяю шаблон вида к созданной копии вида и хочу получить геометрию элементов (а именно BoundingBox или LocationPoint) которые стали видны на созданной копии вида (но не видны на исходном виде).
Я встречал решения через uidoc.RequestViewChange( view ), uidoc.RefreshActiveView(), но совсем понял как это реализовать для моей ситуации и возможно ли вообще. Также встречал решения как можно отсортировать по свойству IsHidden or not..
Вопрос в следующем работает ли сейчас FilteredElementCollector(doc, newId) либо есть какой-то другой метод получения элементов из только созданной копии плана?

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Вызови document.Regenerate() после создания нового вида, затем уже работай с FilteredElementCollector

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Александр, спасибо за отклик!
 :)
Посмотрел API "Use this method to force update to the document after a group of changes. Note that when a transaction is committed there is an automatic call to regenerate the document."
В моём случае я создаю вид и выполняю поиск через FilteredElementCollector в разных нодах и по завершения транзакции в ноде копирования вида происходит автоматическая регенерация документа и получаю новый ViewId на выходе. Проблема заключается в том, что когда я использую FilteredElementCollector(doc, ViewId)... то берётся (BoundingBox) элементов из старого вида...
На данный момент я проблему решил через elem.get_Geometry(Options()).GetBoundingBox(), но не понимаю почему не могу использовать просто BoundingBox элементов из нового вида через elem.BoundingBox[newView]...

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Ноды? Про динамо, поди, речь? Тогда не знаю, не в теме.

Но вообще как бы поиск элементов и получение bounding box вещи то не связанные. Кроме того ты вроде как копируешь вид (по крайней мере, ты упоминал о view.Duplicate)

Обычно в случае изменения чего-то в модели и получения информации достаточно Regenerate-а. Если вдруг нет (такое иногда встречается), то помогает TransactionGroup, в котором можно открыть транзакцию, что-то изменить в модели, закоммитить, потом что-то сделать ещё и в конце, откатить весь TransactionGroup

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Да, это в Dynamo.
Да, я копирую вид и применяю к нему новый шаблон вида. В результате у меня на виде становятся видны элементы, которые не были видны на исходном виде. Но вот получить к ним доступ в новом виде не могу. FilteredElementCollector(doc, ViewId) даже когда ViewId это Id нового вида почему-то эти элементы не видит... Про TransactionGroup тоже слышал, но в данном случае я не хочу пошагово откатывать и видеть историю и просто получить доступ к элементам в новом виде с новым шаблоном вида

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Если смотреть API, то есть такой конструктор
Constructs a new FilteredElementCollector that will search and filter the visible elements in a view.
public FilteredElementCollector(
Document document,
ElementId viewId
)
Однако в самой документации "A FilteredElementCollector based on a view will only contain elements visible in the current view. You cannot retrieve elements that are not graphical or elements that are invisible. A FilteredElementCollector based on a document retrieves all elements in the document including invisible elements and non-graphical elements"
Собственно когда я запускаю скрипт я нахожусь в одном ActiveView (current). В процессе у меня создаётся новый вид и я получаю его (newView). Но когда использую фильтр по конструктору выше и вместо ElementId viewId подставляю newView.Id то "пытаюсь" получить видимые элементы нового вида.

По поводу: Regenerate() and AutoJoinElements() may only be called inside an open transaction.

Скорее всего как я и думал, просто этот конструктор отрабатывает только в том случае, если я пишу FilteredElementCollector(doc,doc.ActiveView.Id) и количество элементов отличается, если бы просто использовали конструктор:
public FilteredElementCollector(
Document document
)
Мне кажется надо смотреть в сторону UIView : "While the View class is the base class for all view types in Revit and keeps tracks of elements in the view, the UIView class contains data about the view windows in the Revit user interface"
The active view can only be changed when:
  • There is no open transaction.
    IsModifiable is false.
    IsReadOnly is false.
    ViewActivating, ViewActivated, and any pre-action of events (such as DocumentSaving or DocumentClosingevents) are not being handled.
А ещё есть "I do not recommend using the Document.ActiveView getter - it is an obsolete property that will likely go away at some point in the future. Please always use the ActiveView property on the UIDocument class" Скорее всего вместо doc.ActiveView надо использовать (буду пробовать): 
UIDocumen.ActiveView Property
The currently active view of the currently active document
public View ActiveView { get; set; }

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Однако тут не всё так просто...
Получал ошибки:
AttributeError: static property 'ActiveView' of 'UIDocument' can only be assigned to through a type, not an instance
Cannot change the active view of a modifiable document (with a transaction curently open).
Exception: Setting active view is temporarily disabled.
и др..
Есть два варианта:
1) method UIDocument.RequestViewChange requests to change the active view by posting a message asynchronously. Unlike setting the ActiveView property, this will not make the change in active view immediately. Instead, the request will be posted to occur when control returns to Revit from the API context. This method is permitted to change the active view from the Idling event or an ExternalEvent callback
2)As a workaround, would it be possible to select the view (using the API), then use PostCommand to set the active view? Then wait for idling again...

Установить через свойство ActiveView напрямую не получается, выдаёт ошибку "Exception: Setting active view is temporarily disabled"
In a sense, that is the case – the system is 'busy', because the Idling event is being processed at the moment.

Удалось реализовать 1 вариант с использованием:
TransactionManager.Instance.ForceCloseTransaction()
uidoc.RequestViewChange(newView)
По окончании работы скрипта, меня перекидывает на вновь созданный вид, однако, ввиду того, что он выполняется асинхронно, я не могу "в нужный момент" получить нужные мне элементы с применённым шаблоном вида с созданного вида

Реализовать 2 вариант не пытался, не совсем ещё разбираюсь с UI событиями Revit. Буду рад, если кто-то даст 2 вариант решения.

Возможно также реализуем и вариант uidoc.ActiveView = newView, однако не в рамках Dynamo. Its worth mentioning that you can’t set the uidoc.ActiveView in Revit’s Idling event. That’s a major drawback for Dynamo, since Dynamo operates inside this event (i.e. its not possible). Instead you need to use RequestViewChange(). Its executes asynchronously, so if you need to set a view first, then perform an action that’s dependent on this event inside the same node then you’ve got a problem

Помогли посты:
https://thebuildingcoder.typepad.com/blog/2017/02/setting-active-view-during-idling.html
https://forum.dynamobim.com/t/changing-active-view-is-tempoerarily-disabled/9267
https://github.com/DynamoDS/Dynamo/issues/3520

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Что, зачем, почему. Написал кучу всего, зачем-то в UIView полез. В API проблем нет (проверил), с нодами динамы что-то не так. Решение следующее, попробуй в питоновском ноде. Это Iron Python Shell, для динамы может что-то переделать надо, не знаю.

Код - Python [Выбрать]
  1. tx = Transaction(doc, "ss")
  2. tx.Start()
  3.  
  4. newView = doc.GetElement(doc.ActiveView.Duplicate(ViewDuplicateOption.WithDetailing))
  5. newView.ViewTemplateId = ElementId(31175)
  6.  
  7. doc.Regenerate()
  8.  
  9. wall = FilteredElementCollector(doc, newView.Id).OfClass(Wall).FirstElement()
  10.  
  11. opt = Options()
  12. opt.View = newView
  13.  
  14. gmtr = wall.get_Geometry(opt)
  15.  
  16. lookup(gmtr)
  17.  
  18. tx.RollBack()

Тут у меня геометрия текущего вида для стенки в тестовом проекте изменяется после применения шаблона, всё работает как часы

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Проблема с выполнением
FilteredElementCollector(doc, newView.Id), который должен собрать видимые элементы с нового вида. В данном случае, дополнительно указываешь в опциях, что хочу получит геометрию стен с нового вида. По идее в wall у тебя уже должна храниться информация о стенах с нового вида, раз мы используем (newView.Id)
Будет ли работать код:
wall = FilteredElementCollector(doc, newView.Id).OfClass(Wall).FirstElement()
opt = Options()
gmtr = wall.get_Geometry(opt)
Ещё проверить версию с opt.View = newView можно. В моём случае стены на начальном виде скрыты (не видны). Насколько понимаю что в данном случае этот вариант не будет работать:
wall = FilteredElementCollector(doc, newView.Id).OfClass(Wall).FirstElement()
opt = Options()
opt.View = newView
gmtr = wall.get_Geometry(opt)

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Проблема с выполнением
FilteredElementCollector(doc, newView.Id), который должен собрать видимые элементы с нового вида

Какие проблемы? Ищет прекрасно.

Будет ли работать код:
Код: [Выделить]

wall = FilteredElementCollector(doc, newView.Id).OfClass(Wall).FirstElement()
opt = Options()
gmtr = wall.get_Geometry(opt)

Будет. Ты получаешь геометрию элемента, не геометрию элемента на конкретном виде.

Насколько понимаю что в данном случае этот вариант не будет работать:
Код: [Выделить]

wall = FilteredElementCollector(doc, newView.Id).OfClass(Wall).FirstElement()
opt = Options()
opt.View = newView
gmtr = wall.get_Geometry(opt)


Будет. Ты же новый вид указываешь, какая разница, видны они на начальном или нет. Кстати, будет работать даже если элемент не виден на newView, вернёт геометрию элемента безотносительно вида.

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Я не могу пользоваться геометрией элемента... и понимаю, что она не зависит от вида...
какая разница, видны они на начальном или нет
разница большая при использовании FilteredElementCollector. Из API про FilteredElementCollector based on a view will only contain elements visible in the current view. You cannot retrieve elements that are not graphical or elements that are invisible
Проблема в том, что элемент может иметь разное отображение на разных уровнях детализации. На высоком уровне я обычно (в зависимости от настроек семейства) могу использовать геометрию элемента, а вот на низком этот элемент отображается как УГО. Мне нужен BoundingBox элемента на низком уровне...
Будет. Ты же новый вид указываешь,
Не будет в рамках работы Dynamo, я описал выше почему. Its worth mentioning that you can’t set the uidoc.ActiveView in Revit’s Idling event. That’s a major drawback for Dynamo, since Dynamo operates inside this event (i.e. its not possible) Потому что сам Dynamo запускается в рамках текущего активного вида и в рамках работы одного скрипта поменять этот текущий активный вид не получится, будет всё время такая ошибка:
Exception: Setting active view is temporarily disabled

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
разница большая при использовании FilteredElementCollector.

Ну и? Подставь нужный вид и работай с ним.

Если разница в детализации - единственная твоя проблема, можешь получать геометрию заданного уровня детализации. Свойство DetailLevel в Options.

you can’t set the uidoc.ActiveView

А зачем устанавливать активный вид?

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
1 нод
newId = view.Duplicate(ViewDuplicateOption.WithDetailing)
...
OUT = newId,StrnewViewsNames,template[0].Name

2 нод:
ViewId = UnwrapElement(IN[0][0])
coll = FilteredElementCollector(doc, ViewId).\
               WherePasses(ElementCategoryFilter(BuiltInCategory.OST_Walls)).\
               WhereElementIsNotElementType().\
               ToElements()
OUT = coll, newView




Ну и? Подставь нужный вид и работай с ним
Не работает...
Если разница в детализации - единственная твоя проблема, можешь получать геометрию заданного уровня детализации. Свойство DetailLevel в Options
Я в принципе коллектором не могу подцепить стены у созданного вида, если они у исходного вида были скрыты. За наводку спасибо!
Грубя говоря, я не могу использовать конструктор для созданных через API видов (работает только для текущего вида doc.ActiveView.Id), поэтому я и смотрел в сторону UI
public FilteredElementCollector(
   Document document,
   ElementId viewId
)

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Регенерацию документа после создания вида, присвоения темплейта вызываешь?

Грубя говоря, я не могу использовать конструктор для созданных через API видов

Эээ, т.е. динамовские обёртки мешают? Используй чистый Revit API, на край, воспользуйся Revit Python Shell, там таких проблем нет

Оффлайн Иван ЛогиновАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Регенерацию документа после создания вида, присвоения темплейта вызываешь?
Регенерация автоматически вызывается по завершении транзакции. Я её завершаю в первом ноде. Во втором ноде уже другая транзакция.
Эээ, т.е. динамовские обёртки мешают?
Да.
Используй чистый Revit API, на край, воспользуйся Revit Python Shell, там таких проблем нет
Пока что цель стоит реализовать с использованием Dynamo и сразу в одной кнопке и создание нового вида и работа с ним...Возможно конструктор:
public FilteredElementCollector(
   Document document,
   ElementId viewId
)
может работать вне Dynamo, не пробовал. Но в блогах по С# тоже писали про проблемы при его использовании..
Используй чистый Revit API, на край, воспользуйся Revit Python Shell
Для конечного пользователя будет штатный функционал Revit из коробки.
Всё что сейчас на Python в Dyanmo буду скорее всего переписывать под C# и возможно там опять вернусь к данной проблеме.