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

ADN Club => AutoCAD .NET API => Тема начата: Alexx от 30-07-2015, 17:43:00

Название: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 30-07-2015, 17:43:00
Добрый день!

Нужно получить список замороженных слоев на подшивке (либо проверить находится ли объект на слое, который заморожен на данной подшивке).

Где-то когда-то нашел примерно следующий код, но в buffer всегда null.

Код - C# [Выбрать]
  1.         public IEnumerable<string> EnumFrozenLayers(Layout layout)
  2.         {
  3.             using (ResultBuffer buffer = layout.GetXDataForApplication("ACAD"))
  4.             {
  5.                 if (buffer == null) yield break;
  6.                 foreach (TypedValue value in buffer)
  7.                 {
  8.                     if (value.TypeCode == 1003)
  9.                         yield return (string)value.Value;
  10.                 }
  11.             }
  12.         }
  13.  

И еще вдогонку парочка вопросов:

1. После того, как для транзакции был вызван Commit(), она не может больше использоваться и нужно создавать новую? Или же можно использовать ее дальше?

2. Транзакция не уничтожается при уничтожении Database?

Спасибо!
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Андрей Бушман от 30-07-2015, 18:35:40
1. После того, как для транзакции был вызван Commit(), она не может больше использоваться и нужно создавать новую? Или же можно использовать ее дальше?
Не может использоваться, нужно создавать новую.

2. Транзакция не уничтожается при уничтожении Database?
Возможно будет интересно почитать это (http://bushman-andrey.blogspot.ru/search/label/Transaction).
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 30-07-2015, 19:26:54
Андрей, спасибо.

Познавательный материал.

Жаль на основной вопрос (про замороженные слои на подшивке) ответа я так и не получил.

Хотя на VBA я делал вот так:

Код - Visual Basic [Выбрать]
  1.     ' Получаем список замороженных слоев для данной подшивки
  2.    Dim frzLayer, frzLayers: Set frzLayers = New Collection
  3.     If UCase(layout.name) <> UCase("Model") Then
  4.         Dim dataType, dataValue
  5.         layout.block(0).GetXData "ACAD", dataType, dataValue
  6.         Dim i: For i = 0 To UBound(dataType) - 1
  7.             If dataType(i) = 1003 Then frzLayers.Add dataValue(i)
  8.         Next
  9.     End If
  10.  

Собственно тут я получал список замороженных слоев не из самого листа, а из первого объекта блока (обычно это видовой экран - но не знаю насколько это правильно и всегда ли первый объект - видовой экран). Думаю, что на C# это должно делаться как-то логичнее и проще.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Андрей Бушман от 30-07-2015, 20:40:50
Жаль на основной вопрос (про замороженные слои на подшивке) ответа я так и не получил.
Подшивка (DST-файл) не имеет слоёв. Слои определены в составе документов, на листы которых ссылается подшивка.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 30-07-2015, 20:59:56
Прошу прощения, я наверное что-то с терминологией напутал - я пока только учусь. Для меня листы всегда были Sheet, а в AutoCAD они вроде как Layout...  ::)

Имелось в виду замороженные слои на листе.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Андрей Бушман от 30-07-2015, 21:04:10
Прошу прощения, я наверное что-то с терминологией напутал - я пока только учусь. Для меня листы всегда были Sheet, а в AutoCAD они вроде как Layout... 
Первая же ссылка в Google (http://adndevblog.typepad.com/autocad/2012/06/list-of-frozen-layers-in-a-paperspace-viewport.html).
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 30-07-2015, 21:14:52
Эту ссылку я видел, но там замороженные листы берутся из видового экрана, выбранного пользователем.
Я так понимаю (могу ошибаться, так как знаком с AutoCAD не так давно), что видовых экранов на листе может быть несколько. Кстати есть же PViewport и Viewport (по-крайней мере в документации к ActiveX они описаны)? Я так понимаю, что PViewport - это видовой экран для листа и он всегда один, а Viewport - это видовой экран модели (типа окошка на листе, в которое смотришь на модель) и их может быть несколько, так? Значит чтобы мне получить замороженные слои на листе, мне нужно взять первый видовой экран листа (PViewport) и вызвать у него GetXData? Так? Или я опять что-то путаю?

Первый пример я тоже не сам придумал, а нашел где-то в интернетах. К сожалению, он не работает.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 30-07-2015, 22:29:28
Я так понимаю (могу ошибаться, так как знаком с AutoCAD не так давно), что видовых экранов на листе может быть несколько.
Это возможно. Но есть основной, который создаётся при инициализации листа. Впрочем это не важно. Имеется метод Layout.GetViewports, который возвращает коллекцию ObjectId видовых экранов листа, которые и следует проанализировать.
P.S.: У листа нет замороженных слоёв - они есть у видового экрана.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 30-07-2015, 22:47:47
Но есть основной, который создаётся при инициализации листа. Впрочем это не важно. Имеется метод Layout.GetViewports, который возвращает коллекцию ObjectId видовых экранов листа, которые и следует проанализировать.

Александр, а как узнать который ВЭ "основной"? У него есть какие-то особенности или он просто будет первым в списке? Остальные ВЭ меня не особенно интересуют, мне нужно узнать заморожен ли слой объекта, находящегося на листе, а не на модели.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 30-07-2015, 23:09:14
У него есть какие-то особенности или он просто будет первым в списке?
Он будет первым в списке.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 11:19:43
Возможно будет интересно почитать это.

Только что попробовал обход довольно большого чертежа по листам->блокам->объектам + фильтры + проверки

Используя StartOpenCloseTransaction получилось около 14 секунд.
Используя StartTransaction вышло около 3 секунд.

Т.е разница в производительности довольно ощутимая даже для клиентского приложения.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 12:12:46
Только что попробовал обход довольно большого чертежа по листам->блокам->объектам + фильтры + проверки

Используя StartOpenCloseTransaction получилось около 14 секунд.
Используя StartTransaction вышло около 3 секунд.

Т.е разница в производительности довольно ощутимая даже для клиентского приложения.
Результат достаточно странный. Особенно если ты открывал все примитивы в режиме "ForRead".
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 12:40:46
Да, открывал в режиме ForRead. Единственное, у меня в коде везде using, что для StartTransaction - нормально, а для StartOpenCloseTransaction - не знаю как :)
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Андрей Бушман от 31-07-2015, 12:49:32
у меня в коде везде using, что для StartTransaction - нормально, а для StartOpenCloseTransaction - не знаю как
Оба класса наследуются от Transaction, который реализует IDisposable. Соответственно использование using для них целесообразно.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 12:52:55
Да, открывал в режиме ForRead.
Тогда совсем странно. Боюсь, что ты что-то перемудрил в коде.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 12:57:26
Оба класса наследуются от Transaction, который реализует IDisposable. Соответственно использование using для них целесообразно.

Андрей, я имел в виду, что все объекты, получаемые при помощи Transaction.GetObject() у меня заключены в using. Насколько я понял, при создании через StartOpenCloseTransaction, транзакция отслеживает все созданные объекты, и при своем уничтожении уничтожает и их. А тут все объекты уже уничтожены вручную, может в этом дело. Хотя думаю вряд ли. В любом случае дело даже скорее не в моем говнокоде, поскольку код один, чертеж один, разница только в способе создании транзакции.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 12:59:49
я имел в виду, что все объекты, получаемые при помощи Transaction.GetObject() у меня заключены в using.
А вот это совсем лишнее. Ни для StartOpenCloseTransaction, ни для StartTransaction этого делать не следует. Только если не пользуешься транзакциями совсем. Я на форуме уже неоднократно писал что такое Dispose() для наследников DBObject в зависимости от того содержатся ли они в Database или нет.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 13:07:31
Я на форуме уже неоднократно писал что такое Dispose() для наследников DBObject в зависимости от того содержатся ли они в Database или нет.

Александр, я постараюсь поискать тему на форуме. Спасибо за совет. Я обычно стараюсь вызывать Dispose() для всего, где он объявлен )))
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 13:13:19
Я обычно стараюсь вызывать Dispose() для всего, где он объявлен )))
Попробуй вызвать Dispose для Database, который ты не создавал при помощи new Database. Я буду долго смеяться.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 13:36:35
Я имел в виду, что вызываю Dispose() для всего, что я сам создавал...
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 13:40:03
Я имел в виду, что вызываю Dispose() для всего, что я сам создавал...
Метод GetObject не создаёт, а открывает существующий объект.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Дмитрий Загорулькин от 31-07-2015, 14:27:47
Ну это смотря в какой трактовке. GetObject не создает нового объекта AutoCAD, но создает новый объект в памяти. Другое дело, что транзакция сама его уничтожает по завершении. Или я не прав?
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 16:48:12
GetObject не создает нового объекта AutoCAD, но создает новый объект в памяти. Другое дело, что транзакция сама его уничтожает по завершении. Или я не прав?
Не прав. Объект уже находится в памяти и GetObject лишь получает указатель на него. При этом устанавливается режим доступа к объекту (ForRead, ForWrite, ForNotify...). По завершении транзакции, а точнее при вызове Close() объекта объект так же не удаляется из памяти.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 17:54:50
Ух ты... Тогда в каком случае нужно использовать Dispose()?
И вообще он что-то делает для объектов, которые получены при помощи GetObject? Или там просто пустой метод?

Объект уже находится в памяти и GetObject лишь получает указатель на него.

В какой момент времени объекты оказываются в памяти?

----

Кстати после того как я убрал using с объектов полученных из StartOpenCloseTransaction-транзакции, проход по чертежу стал намного быстрее работать, но все равно заметно, что со StartTransaction немного быстрее. К тому же столкнулся с проблемой, что при получении StartOpenCloseTransaction я при печати не мог установить текущий лист при помощи ManagerLayout...
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 18:05:55
Почитай: http://adn-cis.org/forum/index.php?topic=737.msg2742#msg2742
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 18:36:27
но все равно заметно, что со StartTransaction немного быстрее.
Всё-равно странно. Транзакция одна или ты запускаешь кучу транзакций?
К тому же столкнулся с проблемой, что при получении StartOpenCloseTransaction я при печати не мог установить текущий лист при помощи ManagerLayout...
И это правильно. Внутри работающей OpenCloseTransaction если объект в ней открыт для чтения, то ты не можешь открыть его же для записи, а при установке текущего листа при помощи LayoutManager требуется такая возможность. Так что в этом случае нужно транзакцию завершать, переключать лист и затем запускать новую транзакцию. Ну или найти какой (или какие) из открытых объектов мешает переключению и закрывать его (или их) при помощи метода Close().
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 18:49:10
Транзакция одна.

На счет StartOpenCloseTransaction и переключения листов все равно странно. Если просто заменить на StartTransaction, то все работает. К тому же LayoutManager - статический класс и листы меняются присвоением имени, а не объекта Layout.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 31-07-2015, 19:26:52
К тому же LayoutManager - статический класс и листы меняются присвоением имени, а не объекта Layout.
И что? Это не означает, что "под ковром" не требуется модификация каких-то объектов чертежа.
Если просто заменить на StartTransaction, то все работает.
Так и должно быть, так как при Transaction можно открывать один и тот же объект и для чтения и для записи, а при OpenCloseTransaction - нельзя. На форуме это обсуждалось не раз.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Alexx от 31-07-2015, 19:31:54
Ааа, так вона оно как. Я тут недавно, еще не успел все прочесть:)
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Дима_ от 31-07-2015, 23:53:45
Не прав. Объект уже находится в памяти и GetObject лишь получает указатель на него.
Скажу честно - меня данное обстоятельство сильно удивило - даже набросал код для проверки (просто по расходу памяти на большое кол-во объектов при GC) - действительно - как минимум на уровне ARX объекты "висят" в памяти (при получении .Net объектов расход идет "побольше" чем на просто указатели - но не зависит от сложности примитива - видимо .Net обертки все-же создаются - это я не проверял - но это и не принципиально). Тогда я вообще не понимаю для чего нужен весь этот "гемор" с транзакциями и приведением объектов (я то думал как-раз для того - чтоб была возможность создавать потенциально неограниченные по размеру чертежи - которые лишь кешируются, для производительности, но не висят в памяти). Зачем это все - доступ-же все равно возможен только из одного потока - вижу только одно "разумное" объяснение когда проектировали систему - хотели как лучше - не манер БД - но видимо "не осилили" - вроде и так сойдет.
Название: Re: Как получить список замороженных слоев на подшивке?
Отправлено: Александр Ривилис от 02-08-2015, 00:47:40
Для подтверждения моей правоты я написал такой код:
Код - C++ [Выбрать]
  1. static void TestId () {
  2.   ads_name en; ads_point p;
  3.   if (acedEntSel(_T("\nSelect ent: "), en, p) != RTNORM)
  4.     return;
  5.   AcDbObjectId id; acdbGetObjectId(id, en);
  6.   acutPrintf(_T("\nid=%p"), (AcDbStub *)id);
  7.   AcDbEntityPointer pEnt(id, AcDb::kForRead);
  8.   if (pEnt.openStatus() == Acad::eOk) {
  9.     acutPrintf(_T("\nptr=%p"), pEnt.object());
  10.   }
  11. }
  12.  
Для одного и того же примитива pEnt.object() стабильно, т.е. имеет один и тот же указатель в памяти.