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

ADN Club => AutoCAD .NET API => Тема начата: Виктор Чекалин от 17-03-2014, 16:53:35

Название: Возможно ли получить все объекты определенного типа
Отправлено: Виктор Чекалин от 17-03-2014, 16:53:35
Добрый день.

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

А есть ли что то подобное в AutoCAD API?
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 17-03-2014, 16:57:50
А есть ли что то подобное в AutoCAD API?
Да. Причем способов несколько:
1. Editor.SelectAll(SelectionFilter)
2. Итерацией по Пространству Модели/Пространству Листа и выборка подходящих по критериям примитивов
3. Итерация по всей базе данных. Но тут можно зацепить и примитивы внутри блоков, а по постановке задачи непонятно нужно ли это.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Виктор Чекалин от 17-03-2014, 17:05:33
Итерация всех объектов это я думаю не то. Выборка всех объектов из БД - явно не быстрая операция.
Код ведь будет примерно такой?
Код - 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 более подходит, судя по описанию и требованиям. Сейчас поглубже в нем покопаюсь.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 17-03-2014, 17:18:41
Виктор! Ау!  :)
Код - C# [Выбрать]
  1. var allObjectIds = tr.GetAllObjects();
Может такое в Revit и работает, но не в AutoCAD .NET API.
Этот код возвращает идентификаторы всех объектов, задействованных в транзакции, т.е. тех которые открыты методом tr.GetObject или добавленных к транзакции при помощи tr.AddNewlyCreatedDBObject, но ни в коем случае не всех, которые есть в Database.
Что касается быстродействия, то по моему опыту итерация по всем примитивам внутри чертежа размером в десяток мегабайт занимает порядка секунды. Так что этого боятся не следует. Editor.SelectAll в конечном итоге использует практически тотже алгоритм. И быстродействия у них одного порядка.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Виктор Чекалин от 17-03-2014, 17:28:40
Ок. Буду иметь ввиду. В 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'овский объект. В гугле пока нашел только как выбирать примитивы.

Приведенный выше код верен или есть более оптимальный способ?
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 17-03-2014, 17:35:53
Тебе нужно узнать имя (или имена) классов для тех примитивов Civil'а и внутри цикла отобрать нужные. В этом тебе поможет сравнение selectedObject.ObjectId.ObjectClass.Name  с именем класса или selectedObject.ObjectId.ObjectClass.DxfName с dxf-именем объекта Civil3D

Так что если ты отбираешь только по имени класса, то тебе даже транзакция не нужна.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Андрей Бушман от 17-03-2014, 17:37:07
Выборка всех объектов из БД - явно не быстрая операция.
Это смотря как посмотреть... Для примера: выборка 736 323 примитивов из базы данных чертежа объёмом более 50 Мб. составила 00:00:00,2781968  (т.е. 1/3 секунды). Достаточно шустро на мой взгляд.

Результаты тестирования разных способов выборки примитивов из БД здесь (https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/database/compare).
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Андрей Бушман от 17-03-2014, 17:47:43
кстати, если идёт речь о выборке всех примитивов из базы данных чертежа и группировки их в по типам в соответствующие Dictionary<String, T>, то я выкладывал код на эту тему здесь (https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/database/dbsearcher). Такая выборка с сортировкой на обозначенных выше данных занимает времени немного больше: 00:00:00,7027717 вместо 00:00:00,2781968, но попрежнему меньше секунды, как видим.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Виктор Чекалин от 17-03-2014, 17:53:43
Андрей, спасибо за статистику.

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

Александр, спасибо за подсказки по поводу имени класса. Информация действительно очень полезной оказалась.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Андрей Бушман от 17-03-2014, 17:55:38
Андрей, спасибо за статистику.
а за обозначенный код с готовым решением???  :o
Цитата: Операция "Ы" и другие приключения Шурика
А компот???©
;D шутки шучу.  мы тут пьянку пьянствуем, вот у меня настроение и поднялось :)

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

UPD а вообще за сам по себе обозначенный мною вариант кода быстрой итерации нужно сказать спасибо всё тому же, надоевшему всем ;) Александру Наумовичу, отвечающему в каждой теме (куда уж без него).
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Виктор Чекалин от 17-03-2014, 18:24:59
За код тоже спасибо :). Однако я не успел его даже просмотреть. Статистики оказалось достаточно:)
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Дмитрий Загорулькин от 19-03-2014, 07:52:46
В сивиле есть специальные методы для получения его объектов определенного типа. К примеру, получить все поверхности в документе: CivilDocument.GetSurfaceIds
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Виктор Чекалин от 19-03-2014, 08:16:58
Дмитрий, к сожалению не для всех объектов есть такая возможность. Поэтому и искал обходной путь.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Дмитрий Загорулькин от 19-03-2014, 10:20:44
Для всех известных мне сивиловских объектов есть возможность извлечения их из тех или иных коллекций. Они не всегда "на верхнем уровне", как те же поверхности. К примеру, виды профиля принадлежат трассам. Значит, путь их получения - сперва получаем все трассы, потом итерацией по трассам получаем виды профилей. Разговор будет более предметным, если Вы назовете тип объектов, которые хотите извлечь ;)
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Андрей Бушман от 19-03-2014, 10:27:59
Код, анализирующий все имеющиеся в базе данных чертежа объекты (абсолютно любые) с попутной их группировкой либо по типам, либо по каким-то иным условиям (произвольным) занимает всего несколько строчек, без необходимости в "специальных методах".
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Виктор Чекалин от 19-03-2014, 11:03:45
Разговор будет более предметным, если Вы назовете тип объектов, которые хотите извлечь ;)
Мне нужно было получить Устройства регулирования потока для конкретной напорной трубопроводной сети. Если говорить языком API, то объекты класса PressureAppurtenance для класса PressureNetwork.
Класс PressureNetwork не содержит метода GetAppertunanceIds().
Поддержка ADN подтвердила, что API для работы с напорными трубопроводными сетями пока еще сыровато. Они добавили появление этого метода в список пожеланий.

Написал вот статью (http://adn-cis.org/kak-poluchit-ustrojstva-regulirovaniya-potoka-dlya-napornoj-truboprovodnoj-seti.html) по этому поводу.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Дмитрий Загорулькин от 19-03-2014, 11:18:09
А... Напорка :) Да, недоработок в ней еще пока полно, даже с пользовательской стороны. Интересная статья, спасибо :)
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Gennadiy от 23-06-2014, 14:04:09
Доброго дня всем.
У меня возник такой вопрос по этой теме:
мне нужно при открытии формы пройтись итерацией по базе данных и сделать определенную выборку,
через SelectAll мне не получить то что мне нужно, т.к. мне нужны также и удаленные (IsErased) объекты.
Воспользовался примерами Андрея Бушмана отсюда
https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/database/dbsearcher (https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/database/dbsearcher).
Но вот пришлось мне открыть чертеж, где TargetDb.Handseed.Value было равно 756 413 642!!!, причем
реально объектов в базе было около 250 000, а на остальные Handle код
bool result = database.TryGetObjectId(h, out id); выдавал false. Так вот такая итерация
у меня занимает времени около 4-5 минут. Отсюда вопрос: можно ли как то ещё получить объекты из базы данных?
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 23-06-2014, 14:11:09
Но вот пришлось мне открыть чертеж, где TargetDb.Handseed.Value было равно 756 413 642!!!, причем
реально объектов в базе было около 250 000
Бывает, хотя чаще всего этот чертеж создается не средствами AutoCAD или в нём действительно было огромное число примитивов, большую часть из которых удалили. Есть выполнить для такого чертежа _WBLOCK *, то метки упорядочиваются.
Ну а дальше всё зависит от того что тебе нужно. Можно пройтись по всем блокам (в том числе и по ModelSpace/PaperSpace) и в каждом из них отбирать то, что тебе нужно. А может тебе достаточно отобрать только в ModelSpace или PaperSpace - без четкой постановки задачи понять сложно.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Gennadiy от 23-06-2014, 14:19:28
Мне нужны все полилинии с определенным ExtensionDictionary, причем также и удаленные из чертежа, для того чтобы повесить на них реакторы на
удаление-восстановление, пока открыта моя палетка (тогда в случае команды "UNDO" они будут появляться в моем списке на палетке)
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 23-06-2014, 14:28:31
Это полилинии непосредственно в ModelSpace/PaperSpace или могут быть внутри блоков? Впрочем в любом случае я выше я уже написал алгоритм - пройтись по таблице блоков заглянув во все описания блоков.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Gennadiy от 23-06-2014, 14:33:03
Полилинии в ModelSpace, но разве ObjectId удаленных примитивов там остаются после удаления? Я думал что их можно достать только из базы.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 23-06-2014, 14:40:51
Полилинии в ModelSpace, но разве ObjectId удаленных примитивов там остаются после удаления? Я думал что их можно достать только из базы.
Остаётся где был. При помощи ObjectId.IsErased можно проверить удалён или нет.
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 23-06-2014, 14:45:27
Думаю что эта ссылка поможет тебе пройтись по пространству Модели и получить все удаленные примитивы в ней: http://adndevblog.typepad.com/autocad/2012/07/indentifying-erased-entities.html
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Gennadiy от 23-06-2014, 15:01:18
То что нужно! Про это
BlockTableRecord withErasedBTR = record.IncludingErased;я не знал.
Большое спасибо!
Название: Re: Возможно ли получить все объекты определенного типа
Отправлено: Александр Ривилис от 23-06-2014, 19:05:36
Я добавил перевод этой статьи на наш сайт: http://adn-cis.org/poisk-udalennyix-primitivov.html