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

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

На работе понадобилось "причесать" стандартный механизм обработки внешних ссылок, используемый в 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). В таком случае последовательность срабатывания будет такова:

Тип реактора Первый параметр Второй параметр
:vlr-xrefSubcommandAttachItem pAttachReactor '(0 nil)
:vlr-xrefSubcommandAttachItem pAttachReactor '(2 "Полное имя ОсновныеРешения.dwg")
:vlr-xrefSubcommandAttachItem pAttachReactor '(3 "Полное имя ОсновныеРешения.dwg")
:vlr-xrefSubcommandAttachItem pAttachReactor '(2 "Полное имя Подоснова.dwg")
:vlr-xrefSubcommandAttachItem pAttachReactor '(3 "Полное имя Подоснова.dwg")
:vlr-xrefSubcommandAttachItem pAttachReactor '(4 nil)

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

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

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

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

Тип реактора Первый параметр Второй параметр
:vlr-xrefSubcommandReloadItem pReloadReactor '(0 0)
:vlr-xrefSubcommandReloadItem pReloadReactor '(2 <Целое число>)
:vlr-xrefSubcommandReloadItem pReloadReactor '(3 <Целое число>)
:vlr-xrefSubcommandReloadItem pReloadReactor '(4 0)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(vl-load-com)

(defun check-object-by-id (id)
                          ;|
*    Поиск указателя на описание блока по его ID
*    Параметры вызова:
  id    ObjectID, для которого надо получить указатель на описание блока
*    Примеры вызова:
(check-object-by-id 85)
|;

  (cdr (assoc id
              ((lambda (/ lst)
                 (vlax-for item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
                   (setq lst (cons (cons (vla-get-objectid item) item) lst))
                   ) ;_ end of vlax-for
                 ) ;_ end of lambda
               )
              ) ;_ end of assoc
       ) ;_ end of cdr
  ) ;_ end of defun

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

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



Поделитесь своим мнением


Я не робот.