Возможно ли получить все объекты определенного типа

Автор Тема: Возможно ли получить все объекты определенного типа  (Прочитано 16040 раз)

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

Оффлайн Виктор ЧекалинАвтор темы

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Добрый день.

В Revit API есть класс FilteredElementCollector, с помощью которого можно выбрать все объекты определенного типа из внутренней базы данных Revit. Если быть точнее, то он он позволяет извлекать из базы данных объекты по различным критериям.

А есть ли что то подобное в AutoCAD API?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А есть ли что то подобное в AutoCAD API?
Да. Причем способов несколько:
1. Editor.SelectAll(SelectionFilter)
2. Итерацией по Пространству Модели/Пространству Листа и выборка подходящих по критериям примитивов
3. Итерация по всей базе данных. Но тут можно зацепить и примитивы внутри блоков, а по постановке задачи непонятно нужно ли это.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Виктор ЧекалинАвтор темы

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Итерация всех объектов это я думаю не то. Выборка всех объектов из БД - явно не быстрая операция.
Код ведь будет примерно такой?
Код - C# [Выбрать]
  1.             var doc = Application.DocumentManager.
  2.                 MdiActiveDocument;
  3.  
  4.             var trMgr = doc.TransactionManager;
  5.  
  6.             List<Line> lines = new List<Line>();
  7.  
  8.             using (var tr = trMgr.StartTransaction())
  9.             {
  10.                 var allObjectIds = tr.GetAllObjects();
  11.  
  12.                 foreach (ObjectId objectId in allObjectIds)
  13.                 {
  14.                     var obj = tr.GetObject(objectId, OpenMode.ForRead);
  15.  
  16.                     if (obj.GetType() == typeof (Line))
  17.                     {
  18.                         lines.Add(obj as Line);
  19.                     }
  20.                 }
  21.             }

Производительность вряд ли будет на высоте.

Пока что Editor.SelectAll более подходит, судя по описанию и требованиям. Сейчас поглубже в нем покопаюсь.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Виктор! Ау!  :)
Код - C# [Выбрать]
  1. var allObjectIds = tr.GetAllObjects();
Может такое в Revit и работает, но не в AutoCAD .NET API.
Этот код возвращает идентификаторы всех объектов, задействованных в транзакции, т.е. тех которые открыты методом tr.GetObject или добавленных к транзакции при помощи tr.AddNewlyCreatedDBObject, но ни в коем случае не всех, которые есть в Database.
Что касается быстродействия, то по моему опыту итерация по всем примитивам внутри чертежа размером в десяток мегабайт занимает порядка секунды. Так что этого боятся не следует. Editor.SelectAll в конечном итоге использует практически тотже алгоритм. И быстродействия у них одного порядка.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Виктор ЧекалинАвтор темы

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Ок. Буду иметь ввиду. В Revit извлечение всех объектов - ресурсоемкая операция.

Но у меня в таком случае возникает закономерный вопрос: а как же тогда правильнее получить все объекты БД?

У меня получилось с помощью все того же Editor.SelectAll() без указания фильтра.

Код - C# [Выбрать]
  1.             var res = ed.SelectAll();
  2.  
  3.             var set = res.Value;
  4.  
  5.  
  6.             using (var t = doc.TransactionManager.StartTransaction())
  7.             {
  8.                 foreach (SelectedObject selectedObject in set)
  9.                 {
  10.                     var obj = t.GetObject(selectedObject.ObjectId, OpenMode.ForRead);
  11.                     Debug.Print(obj.GetType().ToString());
  12.                 }
  13.             }

С фильтром быстро разобраться не получилось, учитывая что мне надо получить не автокадовский примитив, а Civil'овский объект. В гугле пока нашел только как выбирать примитивы.

Приведенный выше код верен или есть более оптимальный способ?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Тебе нужно узнать имя (или имена) классов для тех примитивов Civil'а и внутри цикла отобрать нужные. В этом тебе поможет сравнение selectedObject.ObjectId.ObjectClass.Name  с именем класса или selectedObject.ObjectId.ObjectClass.DxfName с dxf-именем объекта Civil3D

Так что если ты отбираешь только по имени класса, то тебе даже транзакция не нужна.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Выборка всех объектов из БД - явно не быстрая операция.
Это смотря как посмотреть... Для примера: выборка 736 323 примитивов из базы данных чертежа объёмом более 50 Мб. составила 00:00:00,2781968  (т.е. 1/3 секунды). Достаточно шустро на мой взгляд.

Результаты тестирования разных способов выборки примитивов из БД здесь.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
кстати, если идёт речь о выборке всех примитивов из базы данных чертежа и группировки их в по типам в соответствующие Dictionary<String, T>, то я выкладывал код на эту тему здесь. Такая выборка с сортировкой на обозначенных выше данных занимает времени немного больше: 00:00:00,7027717 вместо 00:00:00,2781968, но попрежнему меньше секунды, как видим.

Оффлайн Виктор ЧекалинАвтор темы

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Андрей, спасибо за статистику.

Действительно, беспокоиться не стоит.

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

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Андрей, спасибо за статистику.
а за обозначенный код с готовым решением???  :o
Цитата: Операция "Ы" и другие приключения Шурика
А компот???©
;D шутки шучу.  мы тут пьянку пьянствуем, вот у меня настроение и поднялось :)

Главное, чтобы в хоте итерации исключений не возникало (я и этот вариант показывал в обозначенном мультике), иначе за время итерации можно успеть правнуков вырастить.

UPD а вообще за сам по себе обозначенный мною вариант кода быстрой итерации нужно сказать спасибо всё тому же, надоевшему всем ;) Александру Наумовичу, отвечающему в каждой теме (куда уж без него).

Оффлайн Виктор ЧекалинАвтор темы

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
За код тоже спасибо :). Однако я не успел его даже просмотреть. Статистики оказалось достаточно:)

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
В сивиле есть специальные методы для получения его объектов определенного типа. К примеру, получить все поверхности в документе: CivilDocument.GetSurfaceIds

Оффлайн Виктор ЧекалинАвтор темы

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
Дмитрий, к сожалению не для всех объектов есть такая возможность. Поэтому и искал обходной путь.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Для всех известных мне сивиловских объектов есть возможность извлечения их из тех или иных коллекций. Они не всегда "на верхнем уровне", как те же поверхности. К примеру, виды профиля принадлежат трассам. Значит, путь их получения - сперва получаем все трассы, потом итерацией по трассам получаем виды профилей. Разговор будет более предметным, если Вы назовете тип объектов, которые хотите извлечь ;)

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Код, анализирующий все имеющиеся в базе данных чертежа объекты (абсолютно любые) с попутной их группировкой либо по типам, либо по каким-то иным условиям (произвольным) занимает всего несколько строчек, без необходимости в "специальных методах".