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

13/08/2015

Реакторы внешних ссылок

Потребовалось мне тут поиграться с реакторами на вставку внешних ссылок. Обнаружились достаточно интересные вещи.

На работе понадобилось "причесать" стандартный механизм обработки внешних ссылок, используемый в AutoCAD. VISRETAIN (о которой недавно была статья) установлена равной 1. Файл подосновы вставляется как вставленная ссылка в файл основных решений. В файле основных решений выключаются и/или замораживаются некоторые слои. Файл, естественно, сохраняется. Потом файл основных решений используется как внешняя ссылка в текущей работе. И вот тут вылезает очень интересная штука: при вставке "основных решений" состояние слоев "подосновы" не подхватывается и берется именно в том виде, в каком оно есть в исходном файле ("подосновы"). Оставлю за скобками правильность такого решения Autodesk, равно как и требования пользователей "брать то состояние слоев, которое есть в файле основных решений" - надо сделать так, чтобы читалось. Понятно, что надо обрабатывать в реакторах. Вот об этом и расскажу.

Входящие условия достаточно просты:

В текущий файл внешней ссылкой вставляется ОсновныеРешения.dwg, внутри которого также есть ссылка (вставленная) на Подоснова.dwg. Вставка выполняется штатными средствами (вручную), никаких дополнительных событий выполнения команды обрабатывать не надо. Поэтому использовались только реакторы типов :vlr-xrefSubcommandAttachItem, :vlr-xrefSubcommandOverlayItem, :vlr-xrefSubcommandReloadItem

Функции, сопоставленные этим событиям, имеют по два параметра: первый - это указатель на реактор (далее pAttachReactor - для события вставки ссылки; pOverlayReactor - для события наложения ссылки; pReloadReactor - для события перезагрузки ссылки), второй - список из двух элементов. Первым элементом списка обязательно идет целое число, показывающее процесс выполнения подкоманды (опции) и может принимать одно из следующих значений:

ЗначениеПояснение
0подкоманда инициирована
2ссылка обрабатывается (для реакторов :vlr-xrefSubcommandAttachItem и :vlr-xrefSubcommandOverlayItem это означает, что ссылка еще не до конца транслирована в текущий документ и получить доступ к ее элементам невозможно)
3ссылка уже обработана ядром AutoCAD, можно обращаться к ее элементам
4подкоманда завершена корректно
5выполнение подкоманды будет прервано
6выполнение команды завершено аварийно

Поскольку меня интересовало только корректное завершение работы команды, то варианты 5 и 6 можно уже не рассматривать. В реакторах вставки ссылки для опций 0 и 4 вторым элементом идет nil, а для 2 и 3 - полное имя вставляемого dwg-файла.

Теперь собственно как происходит вставка ОсновныеРешения.dwg в текущий документ? Тут все будет зависеть от того, каким мы образом его вставляем: как вставленную (Attached) или наложенную (Overlayed). Рассмотрим оба варианта.

Допустим, мы вставляем ссылку как вставленную (Attach). В таком случае последовательность срабатывания будет такова:
Тип реактораПервый параметрВторой параметр
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor
Код: [Выделить]
  1. '(2 "Полное имя ОсновныеРешения.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor
Код: [Выделить]
  1. '(3 "Полное имя ОсновныеРешения.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor
Код: [Выделить]
  1. '(2 "Полное имя Подоснова.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor
Код: [Выделить]
  1. '(3 "Полное имя Подоснова.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor

Но стоит нам начать вставлять ссылку как наложенную (Overlay), как картина тут же меняется:

Тип реактораПервый параметрВторой параметр
Код: [Выделить]
  1. :vlr-xrefSubcommandOverlayItem
pOverlayReactor
Код: [Выделить]
  1. :vlr-xrefSubcommandOverlayItem
pOverlayReactor
Код: [Выделить]
  1. '(2 "Полное имя ОсновныеРешения.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandOverlayItem
pOverlayReactor
Код: [Выделить]
  1. '(3 "Полное имя ОсновныеРешения.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor
Код: [Выделить]
  1. '(2 "Полное имя Подоснова.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandAttachItem
pAttachReactor
Код: [Выделить]
  1. '(3 "Полное имя Подоснова.dwg")
Код: [Выделить]
  1. :vlr-xrefSubcommandOverlayItem
pOverlayReactor

Как видно, используются уже два реактора, при этом один из них (:vlr-xrefSubcommandOverlayItem) отрабатывает по полной программе, а второй :vlr-xrefSubcommandAttachItem) - только частично: он не вызывается с данными, указывающими на корректное завершение работы подкоманды. При написании собственного обработчика этот момент надо будет учитывать.

Теперь попробуем для вставленной ссылки поменять ее тип - со вставленной на наложенную или наоборот. В таком случае срабатывают уже не реакторы вставки, а :vlr-xrefSubcommandReloadItem. Этот реактор немного отличается от уже рассмотренных: сопоставленная ему функция также имеет два параметра. Первый - указатель на сам реактор, а второй - список из двух чисел. Смысл первого числа уже описывался выше, а второе - это ID объекта внешней ссылки или 0.

Тип реактораПервый параметрВторой параметр
Код: [Выделить]
  1. :vlr-xrefSubcommandReloadItem
pReloadReactor
Код: [Выделить]
  1. :vlr-xrefSubcommandReloadItem
pReloadReactor
Код: [Выделить]
  1. '(2 ЦелоеЧисло)
Код: [Выделить]
  1. :vlr-xrefSubcommandReloadItem
pReloadReactor
Код: [Выделить]
  1. '(3 ЦелоеЧисло)
Код: [Выделить]
  1. :vlr-xrefSubcommandReloadItem
pReloadReactor

Если Вы решите в этом реакторе использовать собственный обработчик, учтите, что стандартные lisp-функции преобразования ObjectID в указатель на объект здесь могут и не сработать. Точнее, говоря, у меня они не сработали в AutoCAD2009 и 2013 (обе версии 64-разрядные) - вплоть до ошибки ядра AutoCAD. Пришлось писать специальную функцию "поиска" указателя на описание блока внешней ссылки по ее ObjectID:

Код - Auto/Visual LISP: [Выделить]
  1. (vl-load-com)
  2.  
  3. (defun check-object-by-id (id)
  4.                           ;|
  5. *    Поиск указателя на описание блока по его ID
  6. *    Параметры вызова:
  7.   id    ObjectID, для которого надо получить указатель на описание блока
  8. *    Примеры вызова:
  9. (check-object-by-id 85)
  10. |;
  11.   (cdr (assoc id
  12.               ((lambda (/ lst)
  13.                  (vlax-for item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
  14.                    (setq lst (cons (cons (vla-get-objectid item) item) lst))
  15.                    ) ;_ end of vlax-for
  16.                  ) ;_ end of lambda
  17.                )
  18.               ) ;_ end of assoc
  19.        ) ;_ end of cdr
  20.   ) ;_ end of defun

Скажу честно - во всех остальных случаях штатные функции vlisp для получения указателя на объект по его ObjectID срабатывали корректно. Так что приведенный код понадобился только в этом конкретном случае.

Теперь в функциях обработки реакторов :vlr-xrefSubcommandOverlayItem и :vlr-xrefSubcommandAttachItem можно проанализировать передаваемые данные, при необходимости прочитать состояние слоев вставляемого файла, и установить соответствующие значения в текущем документе.

Автор: Алексей Кулик

Обсуждение: http://adn-cis.org/forum/index.php?topic=2910

Опубликовано 13.08.2015