Не работает функция Face.Triangulate(), вызванная в другом потоке.

Автор Тема: Не работает функция Face.Triangulate(), вызванная в другом потоке.  (Прочитано 5663 раз)

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

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

  • ADN OPEN
  • Сообщений: 6
  • Карма: -1
Всем доброго времени суток. Столкнулся с проблемой при работе с функцией Face.Triangulate() у одного объекта (файл проекта можно скачать по ссылке https://drive.google.com/open?id=1ZTj1-LvnGwudGE5qJRHa9uheDji796y1, id объекта 2396118).
Функция Face.Triangulate(), выполненная в потоке Revit, нижней (самой сложной) поверхности этого объекта выдает:
•   982 треугольника с параметром 0;
•   4262 треугольника с параметром по умолчанию;
•   10942 треугольника с параметром 1.
Естественно, эта же функция, выполненная в отдельном потоке должна выдавать те же результаты. Это подтверждается на практике для большого количества других объектов. Однако, вот что мы имеем на деле:
•   4759 треугольников с параметром 0;
•   4759 треугольников с параметром по умолчанию;
•   4759 треугольников с параметром 1.
Другими словами, мало того, что количество треугольников не совпадает, так еще и оно не изменяется при изменении параметра.
И самая основная проблема: после завершения работы плагина Revit вообще выдает ошибку и закрывается принудительно.
Код:
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.Revit.Attributes;
  3. using Autodesk.Revit.DB;
  4. using Autodesk.Revit.UI;
  5. using System.Threading;
  6.  
  7. namespace RevitGeometry
  8. {
  9.     [Transaction(TransactionMode.Manual)]
  10.     public sealed partial class TriangulateGeometry : IExternalCommand
  11.     {
  12.         private static void GetGeometry(object commandData)
  13.         {
  14.             Document document = ((ExternalCommandData)commandData).Application.ActiveUIDocument.Document;
  15.  
  16.             Element element = document.GetElement(new ElementId(2396118));
  17.  
  18.             GeometryElement geometryElement = element.get_Geometry(new Options { DetailLevel = ViewDetailLevel.Fine });
  19.             foreach (GeometryObject geometryObject in geometryElement)
  20.             {
  21.                 Solid solid = geometryObject as Solid;
  22.  
  23.                 Face face = solid.Faces.get_Item(0);
  24.  
  25.                 Mesh mesh = face.Triangulate(0);
  26.             }
  27.         }
  28.  
  29.         Result IExternalCommand.Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
  30.         {
  31.             try
  32.             {
  33. #if DEBUG
  34.                 System.Diagnostics.Debugger.Launch();
  35. #endif
  36.                 //works
  37.                 //GetGeometry(commandData);
  38.  
  39.                 //doesn't work
  40.                 Thread secondThread = new Thread(GetGeometry);
  41.                 secondThread.Start(commandData);
  42.                 secondThread.Join();
  43.             }
  44.             catch (Exception)
  45.             {
  46.                 return Result.Failed;
  47.             }
  48.  
  49.             return Result.Succeeded;
  50.         }
  51.     }
  52. }
  53.  

Отмечено как Решение Александр Ривилис 12-03-2018, 18:20:53

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Ревит однопоточный и нельзя обращаться к его базе из другого потока. Точнее, можно обращаться для получения данных, но для какого-либо редактирования - уже нет. Для этого уже нужно реализовать специальный класс IExternalEvenet.
Возможно, для работы метода Triangulate вызываются какие-либо изменения (перерисовка геометрии, например) и поэтому падает Ревит у вас.
Кстати, как падает-то? Ошибку выдает какую? Может стоит для начала обернуть в try{} catch(){}?

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

  • ADN OPEN
  • Сообщений: 6
  • Карма: -1
Вот так падает:

try-catch обертка не помогает, поскольку в процессе работы никаких исключений не возникает, Revit падает уже после "успешного" завершения работы плагина.
Тогда вопрос можно переформулировать по-другому: что такого есть в этом объекте, чего нет во многих других, что заставляет плагин некорректно работать в другом потоке?

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
1. Я вам уже сказал - Ревит однопоточный и не позволяет с собой работать из другого потока
2. Зачем вообще второй поток?
3. С чего вы взяли, что падает на этом методе?
4. Вы можете сделать тестовый проект и приложить его к теме?

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

  • ADN OPEN
  • Сообщений: 6
  • Карма: -1
Второй поток нужен, чтобы во время работы большого плагина не зависало ничего и можно было отменить работу;
Потому что если этот метод убрать - все работает;
Тестовый проект приложен (ну я надеюсь по крайней мере), его можно скачать по ссылке во втором предложении в скобках.
https://drive.google.com/file/d/1ZTj1-LvnGwudGE5qJRHa9uheDji796y1/view

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Второй поток нужен, чтобы во время работы большого плагина не зависало ничего и можно было отменить работу;
Я даже разбираться не буду с примером и просто спрошу - как вы себе это представляете??? Типа работает команда, а я в этот момент что-то могу делать в Ревите??

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

  • ADN OPEN
  • Сообщений: 6
  • Карма: -1
Нет конечно. При работе плагина из потока Ревита, он может зависнуть (полоса загрузки остановится), его нельзя отменить (потому что нельзя никуда нажать), Ревит может стать черным (что не очень приятно видеть) и т.п. Второй поток нужен, чтобы я мог в браузере, например, что-то делать и не бояться, что у меня уже давно завис плагин, а я даже отменить его не смогу.

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Bojan
1. Как уже написал Александр Пекшев aka Modis использовать потоки в Revit нельзя. Во всяком случае так, как Вы делаете.
2. Для прерывания выполнения второй поток не нужен. Нужно просто отслеживать нажатие клавиатуры.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Нет конечно. При работе плагина из потока Ревита, он может зависнуть (полоса загрузки остановится), его нельзя отменить (потому что нельзя никуда нажать), Ревит может стать черным (что не очень приятно видеть) и т.п. Второй поток нужен, чтобы я мог в браузере, например, что-то делать и не бояться, что у меня уже давно завис плагин, а я даже отменить его не смогу.
Нет, так нельзя делать. Третий раз говорю - Ревит однопоточный и любые действия с БД проекта требуют работу только в текущем потоке Ревита.
Единственное, что вы можете - это запустить в другом потоке окно с отображением прогресса. А вот чтобы мочь процесс работы еще и отменить из этого окна - это уже нужно помучаться.
Но то, что вы хотите - нельзя сделать

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 6
  • Карма: -1
Слушайте, я просто привел пример, а вы зачем-то начали отвечать не на мой вопрос. Если я правильно понял все вышеизложенное, то по делу:
1. Нельзя понять, почему именно на этому объекте не работает;
2. Корректность работы функции Face.Triangulate() нельзя гарантировать во внешнем потоке. Кроме того, нельзя сказать в каких случаях она будет корректная, а в каких нет.

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Bojan
Ответ на поставленный вопрос: нельзя использовать внешние потоки (Thread) в Revit API. Точка. Дале тебе начали подсказывать как следует выкрутится в данной ситуации. Что не так?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 6
  • Карма: -1
Это не ответ на поставленный вопрос (нельзя использовать внешние потоки (Tread) в Revit API), потому что не было вопроса: "Можно ли использовать внешние потоки (Tread) в Revit API?". Вопрос в явном виде не был поставлен, но по-моему достаточно очевидно, что вопрос в следующем: "Почему функция Face.Triangulate() некорректно работает из внешнего потока?" Ответ на этот вопрос прозвучал почти сразу: "Ревит однопоточный и нельзя обращаться к его базе из другого потока...", но во время этого ответа прозвучали встречные вопросы, на которые я ответил и задал второй вопрос по теме: "Что такого есть в этом объекте, чего нет во многих других, что заставляет плагин некорректно работать в другом потоке?" Ответ на него так и не прозвучал, поэтому я и ответил на него сам, просуммировав все что вы сказали: "Нельзя понять, почему именно на этому объекте не работает". Вот это полный ответ на два основных вопроса, который можно было дать сразу, а не уходить в сторону, поскольку в процессе цепочки вопросов-ответов ничего нового вы и я не узнали.

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Bojan, вы вообще ничего не поняли? Этот метод поэтому и не работает, что нельзя в Ревите обращаться к БД из другого потока. Также не будут и сотни других методов работать по той же самой причине! Причем я вам в первом же ответе выдвинул одно из предположений на вопрос Почему конкретно этот метод
Возможно, для работы метода Triangulate вызываются какие-либо изменения (перерисовка геометрии, например) и поэтому падает Ревит у вас.

Оффлайн WhiteShark

  • ADN OPEN
  • Сообщений: 2
  • Карма: 1
Bojan
Для начала оберните ваш трэд в try catch. Тогда будет понятно был ли там exception. Ваш имеющийся catch никогда не поймает exception в новом трэде "secondThread"

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Кстати, ваш код падает не на строчке
Код - C# [Выбрать]
  1. [s]Mesh mesh = face.Triangulate(0);[/s]
а на строчке
Код - C# [Выбрать]
  1. [s]foreach (GeometryObject geometryObject in geometryElement)[/s]
Потому что geometryElement равен null! А знаете почему? Потому что НЕЛЬЗЯ РАБОТАТЬ С БД ПРОЕКТА ИЗ ДРУГОГО ПОТОКА![/b]

Соврал - метод отрабатывает и Ревит падает. Причина конечна ясна, но конкретно её объяснить сложно

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus


Надеюсь официальная справка отобьет желание дальше спорить на глупые темы

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Александр Пекшев aka Modis
Я отметил твой ответ как Решение, так как он в точности соответствует природе ошибки.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн maksl

  • ADN OPEN
  • Сообщений: 21
  • Карма: 4

2. Для прерывания выполнения второй поток не нужен. Нужно просто отслеживать нажатие клавиатуры.

я, возможно, в лыжи обут, но не работает все так просто. беглое курение msdn показало, что события типа button_click не проходят, пока поток занят в другом цикле. и мои тесты показывают то же самое.

Вот тут я новую тему создал: http://adn-cis.org/forum/index.php?topic=8366.0

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
беглое курение msdn показало, что события типа button_click не проходят, пока поток занят в другом цикле. и мои тесты показывают то же самое.
Нужно сделать так, чтобы поток не был "постоянно занят в другом цикле".
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение