AutoLISP: Работа с реакторами
| Правила | Регистрация | Пользователи | Сообщения за день |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > AutoLISP: Работа с реакторами

AutoLISP: Работа с реакторами

Ответ
Поиск в этой теме
Непрочитано 28.11.2008, 12:43 #1
AutoLISP: Работа с реакторами
Supermax
 
Руководитель фирмы
 
Москва
Регистрация: 28.03.2007
Сообщений: 1,831

В этой теме я подробно изложу все тонкости работы с реакторами.

В замечательной книге Н.Н. Полещука "AutoLISP и Visual Lisp в среде AutoCAD" есть целая глава, посвященная этому, очень сильному инструменту, но она писалась, по всей видимости, в последнюю очередь и сил на подробное освещение всех нюансов, видимо не хватило.
Так заполним же этот пробел.

Я не буду повторять написанное в этой книге! Я буду давать данные, опираясь на предположение, что вы имеете эту книгу и читали эту главу.

И так:

Есть временные реакторы и постоянные. Временные работают только в текущем сеансе редактирования рисунка, постоянные - встраиваются в рисунок и срабатывают везде, где этот рисунок открыт.

НО!

Без подгруженных функций, которые эти реакторы должны запускать дело не пойдет, а вот их-то и проблема подгрузить.

Если речь идет об универсальных функциях - нет проблем. Добавляем их в файл acaddoc.lsp и все. Они будут подгружаться во все открываемые документы. Но разве это надо? Правильно, вот и я подумал - не надо. Надо, чтобы из той директории, в которой лежит файл с рисунком, запускался (в случае ниличия) одноименный файл *.lsp с функциями, нужными только этому рисунку (раз в него реакторы понатыканы).

Вот я и сделал такой файл acaddoc.lsp, который не содержит функций, но который при каждом открытии рисунка проверяет, а нет ли в этой же директории такого же лисп-файла и если есть - подгружает все, что в нем в этот рисунок.

Получилось что-то типа проекта, состоящего из файла DWG и прилагаемых к нему файлов.

Вот код файла acaddoc.lsp.
Код:
[Выделить все]
(vl-load-com)
(setq actdoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(setq win-tit (vla-get-WindowTitle actdoc))
(if (vl-file-directory-p (vl-filename-directory win-tit))
 (progn
  (setq win-tit 
   (vl-list->string 
    (reverse 
     (append 
      '(112 115 108) 
       (cdddr 
        (reverse 
         (vl-string->list win-tit)
        )
       )
      )
     )
    )
   )
  (if (findfile win-tit) 
   (load win-tit)
  )
 )
)
(setq win-tit nil)
Тут можно и сообщение добавить, о том, что функции введены и если такой файл есть, то добавить этот текст в него.
Просмотров: 12696
 
Непрочитано 28.11.2008, 13:04
#2
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Ты сам-то понял, чего хотел?
Реакторы сами по себе достаточно опасная штука. Вдобавок в каждом конкретном случае (имею в виду прежде всего вертикальные решения) надо проверять корректность работы этого реактора. Я уже не говорю о "навесках" типа СПДС / MechaniCS etc,- там свои тараканы могут встречаться.
Постоянные реакторы навесить можно, и ты прав в том плане, что
Цитата:
Без подгруженных функций, которые эти реакторы (постоянные - дополнение мое) должны запускать дело не пойдет<...>
Мало того что не пойдет, еще и огребешь по полной, если реактор постоянный и навешен на объект.
А вот что "проблема их загрузить" - извини, это тебе просто лень заниматься. Прописывается код с реакторами в автозагрузку и работай как хочешь.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 28.11.2008, 13:12
#3
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


В автозагрузку все не пропишешь, и надо ли оно? Вот есть у меня файл с прикрученным реактором, так что, из-за него во все рисунки загружать нужные только ему лиспы?
И если нет в рисунке таких функций - просто пишет - нет такой функции. Что тут огребать? На нет и суда нет.

Потом, я уже просек, что надо после срабатывания реактора, ставить в очередь выполнение нужных тебе функций и сразу из него сваливать. То есть функции начнут выполняться только после завершения обработки события и окончании работы реактора.

Код сейчас подгоню.
Supermax вне форума  
 
Непрочитано 28.11.2008, 13:25
#4
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Извини, но то, что ты говоришь - фигня чистой воды. Тебе никто не может помешать запускать свои функции как в момент срабатывания реактора, так и в момент выхода из него.
А то, что "функция отсутствует" - это до поры до времени. Когда файл рухнет или аудит твои объекты порушит - вот тогда ты поймешь, о чем я говорил. Я такое словил на 2005 ADT, с тех пор либо гарантированная загрузка реакторов, либо без постоянных. Второе предпочтительнее.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 28.11.2008, 14:33
#5
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Не фигня! Стр. 788 раздел 9.8
1. 3-е ограничение. Цитирую:

Цитата:
В функциях действия нельзя использовать такие интерактивные функции, как getkword, getpoint, entsel и т.д. Кроме того, запрещается в функциях действия применять функцию command.
4-е ограничение
Цитата:
Нельзя вызывать диалоговые окна во время обработки событий. Функции, работающие с диалоговыми окнами, относятся к интерактивным функциям и поэтому будут конфликтовать с работой реакторов.
5-е ограничение
Цитата:
Объект, который стал источником события, не может быть модифицирован из функции действия, реагирующей на это событие.

Так вот, мне надо нарушить все эти три правила.

Мне надо, при переключении в динамическом блоке значения свойства "Настройка блока" со значения "Блок настроен" на значение "Настроить", чтобы сработал реактор, проверил значение свойства и если оно переключено - запустил программу перестройки блока.

Проверить можно напрямую из функции действия, а вот все остальное - только дождавшись окончания работы реактора. И КАК я уже знаю.

Сейчас будет код. погоди.
Supermax вне форума  
 
Автор темы   Непрочитано 28.11.2008, 15:46
#6
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Создаем реактор объекта:
Код:
[Выделить все]
; Указываем на нужный нам объект:
(setq obj (vlax-ename->vla-object (car (entsel))))
;Устанавливаем на него реактор модификации 
(setq reactor1 (vlr-object-reactor (list obj) nil (list '(:VLR-modified . vlr-sdd22))))
;Делаем его постоянным
(vlr-pers reactor1) ;Пардон, тут ошибка была
Для очистки рисунка от реакторов запускаем
Код:
[Выделить все]
(vlr-remove-all)
Если теперь пошевелить объект, то будет срабатывать реактор. Но нужна функция vlr-sdd22 хоть в точечной паре она указана без аргументов, ее надо делать с тремя аргументами.

Вариант 1 (нельзя так делать!)
Код:
[Выделить все]
(defun VLR-SDD22 (a-object b-vlr-object c-data / ) 
  (vla-SendCommand 
    (vla-get-ActiveDocument (vlax-get-acad-object)) 
    "(alert \"Привет!\") ")
(alert "Пока еще нет привета")
)
Обращаю внимание на то, что "Пока еще нет привета" стоит в лиспе после "Привет", а срабатывает раньше его. Почему? - Да потому, что vla-SendCommand передает данные в ком. строку как бы из вне, а из вне все выстраивается в очередь. Пока реактор не отработает свое, он будет занимать Автокад, а как только закончит это делать - вуаля, все, что в очереди будет выполнено.

Второй вариант: (так тоже нельзя делать!)
Код:
[Выделить все]
;Функция запускаемая по окончании действия реактора
(defun lisp_Onobj () (alert "Привет"))
;Функция действия самого реактора
(defun VLR-SDD22 (a-object b-vlr-object c-data / ) 
(setq ScriptControl (vlax-get-or-create-object "MSScriptControl.ScriptControl"))
(vlax-put-property ScriptControl "Language" "VBScript")
(vlax-invoke-method ScriptControl "AddCode" "
  Set AutoCAD = GetObject(, \"AutoCAD.Application\")
  Set ActiveDocument = AutoCAD.ActiveDocument
  ActiveDocument.SendCommand \"(lisp_Onobj) \"
")
)
Аналогичная история, только в скрипте можно еще очень многое сделать недоступное в Автокаде. Точно так же посыл в командную строку выстраивается в очередь и обрабатывается только после окончания работы самого реактора.

Третий вариант: (Правильный)

Код:
[Выделить все]
;Функция запускаемая по окончании действия реактора
(defun lisp_Onobj () 
;освобождаем объект Script
(vl-catch-all-apply '(lambda () (vlax-release-object script)))
(alert "Привет"))
;Функция действия самого реактора
(defun VLR-SDD22 (a-object b-vlr-object c-data / ) 
;Сохраняем указатель на объект - блок "линия
 (setq stat-object a-object)
;Сохраняем указатель на объект - реактор
 (setq stat-vlr-object b-vlr-object)
;записываем имя временного файла
(setq Fdcl "Sel555.vbs")
;Создаем путь к временному файлу
(setq Fdcl (strcat (VL-FILENAME-DIRECTORY(vl-filename-mktemp Fdcl)) "\\" Fdcl))   
(vl-file-delete Fdcl)  ;Если есть такой файл, то его убить, поскольку он каждый раз создается с 0.

(setq dsl0055 (open Fdcl "w")) ;Открываем и заполняем файл Sel555.vbs 
(write-line "Set AutoCAD = GetObject(, \"AutoCAD.Application\")" dsl0055)
(write-line "Set ActiveDocument = AutoCAD.ActiveDocument" dsl0055)
(write-line "WScript.Sleep 10" dsl0055)
(write-line "ActiveDocument.SendCommand \"(lisp_Onobj) \"" dsl0055)
(close dsl0055)
;Запускаем скрипт.
(setq script (DwgRu-WScript-Exec Fdcl ""))

;Сваливаем из реактора
)

Последний раз редактировалось Supermax, 30.11.2008 в 14:59.
Supermax вне форума  
 
Автор темы   Непрочитано 28.11.2008, 15:54
#7
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Таким макаром работают все функции, в состав которых входит и command, и entget, и DCL панели и прочее. Можно этот же объект удалять из списка объектов на обработку реактором и наоборот, добавлять. Я уж молчу, что его можно вообще весь переделать и он останется привязан к реактору (разумеется его сначала удаляют из списка, переделывают, и опять добавляют к списку).
Supermax вне форума  
 
Непрочитано 28.11.2008, 16:15
#8
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


1. Устойчивость такого реактора находится под очень большим вопросом.
2. Попытка навесить такое на CustomObject (объект СПДС / MechaniCS / ADT) при условии подгруженного ObjectEnabler'a или соответствующего arx может развалить AutoCAD
3. То же, что и 2, но без подгруженного OE или arx может завалить acad.exe при открытии файла с условием подгрузки сначала arx, а потом соответствующего реактора. Иногда срабатывает и при обратном порядке загрузки.*
4. Если через SendCommand в реакторе, привязанном к объекту, ты (случайно или нет - дело десятое) пошлешь команду на изменение этого же объекта (удаление тоже, по-моему, считается изменением), у тебя пойдет бесконечный цикл. Вдобавок рано или поздно получишь либо переполнение стека, либо ошибку 0x000005 (ну или сколько там нулей). Выход, как правило, только один - перезапуск acad.exe.
---
Резюме: не иди в лоб, ищи обходные пути.
---
Добавлено:
* порядок загрузки лично мне отрегулировать не удавалось ни разу.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 28.11.2008, 16:40
#9
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Ай, ай, ай! Опять ты не понял.

Вышел я уже из реактора! ВЫШЕЛ!

Пока был в функции действия, понавтыкал в очередь запуск других функций, но не выполнял их, пока не выйду, а когда вышел, они сами запустились. Я же указал прямо, на тот факт, что выполняется все, вплоть до самого конца функции действия, а то, что послано через vla-SendCommand, выполнится только когда реакция закончится. Это все равно, что просто запустить функцию не трогая объекты.

Весь реактор из двух строчек, и нет в нем никаких действий по отношению к объекту, который вызвал эту реакцию реактора.
Но, вот когда обработка события завершена и реактор опять переходит в спящий режим, начинают срабатывать лиспы, которые не могли пробиться к ком. строке, из-за работы реактора.
Ну что может натворить функция, чье имя торчит в очереди? типа "(lisp_Onobj) ".
Supermax вне форума  
 
Непрочитано 28.11.2008, 16:44
#10
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Вызов ком.строки из-под реактора даже через SendCommand лично у меня несколько раз убивал acad. Я (надеюсь) не дурнее паровоза и вызывал SendCommand из функции окончания реактора. Поэтому я и сказал насчет устойчивости.
Теперь навесь на любой объект свой реактор изменения объекта и выполни (в конце, естественно) любую команду, затрагивающую этот объект.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 28.11.2008, 16:49
#11
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


По поводу бесконечного цикла.
Есть много способов его устроить, но разве нам это надо?
Я написал, а ты не прочитал, что
Цитата:
... (разумеется его сначала удаляют из списка, переделывают, и опять добавляют к списку).
Естественно, что перед модификацией надо удалить из этого реактора указатель на объект, к которому он привязан, а после модификации, добавить указатель на этот объект к этому реактору (даже если он стал другим).
Supermax вне форума  
 
Непрочитано 28.11.2008, 17:00
#12
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Замечательно! Представь себе ситуацию:
1. Объект с хендлом "1234"
2. На его изменение "повешен" реактор с SendCommand
3. После изменения объекта срабатывает реактор, затрагивающий этот объект.
Каковы будут твои действия для решения проблемы п.3? Ведь потом надо обратно реактор повесить...
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 28.11.2008, 17:30
#13
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Ща, сварганю.
Есть объект с повешанным на него реактором. К примеру - динамический блок "Линия". Надо при попытке изменить длинну линии, устанавливать ее длинну в нужное значение. Сойдет такой пример?
Supermax вне форума  
 
Автор темы   Непрочитано 28.11.2008, 20:06
#14
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Даю файл DWG с динамическим блоком "Линия" и установленным на нем реактором, а также файл с двумя функциями к нему.

Код:
[Выделить все]
(vl-load-com)
;============= Функция редактирования динамического блока "Линия" =================
(defun modline (/ S_Document S_ModelSpace point-temp)
;Получаем указатели на активный документ и пространство модели
  (setq S_Document (vla-get-ActiveDocument (vlax-get-acad-object)))
  (setq S_ModelSpace (vla-get-ModelSpace S_Document))

;Создаем временный объект "точка"
(setq point-temp (vla-AddPoint S_ModelSpace (vlax-3D-point '(0.0 0.0 0.0))))

;Добавляем временный объект в список объектов реактора
(vlr-owner-add stat-vlr-object point-temp)

;Удаляем из списка объектов реактора наш блок "Линия"
(vlr-owner-remove stat-vlr-object stat-object)

;Создаем список всех свойств блока "Линия"
  (setq
    lst_temp
     (vlax-safearray->list
       (vlax-variant-value (vla-GetDynamicBlockProperties stat-object))
     )
  )

;Получаем указатель на свойство "Distance"
  (foreach item	lst_temp
    (if	(= (vla-get-PropertyName item) "Distance")
      (setq naimenov item)
    )
  )

;Устанавливаем нужную длинну линии
(vla-put-Value naimenov 500.00)

;Добавляем блок "Линия" в список объектов реактора
(vlr-owner-add stat-vlr-object stat-object)

;Удаляем из списка объектов реактора временный объект "точка"
(vlr-owner-remove stat-vlr-object point-temp)

;Убиваем временный объект "точка"
(vla-Delete point-temp)
)

;============ Функция действия реактора к блоку "Линия" ============================

(defun VLR-SDD22 (a-object b-vlr-object c-data / )

;Сохраняем указатель на объект - блок "линия
 (setq stat-object a-object)

;Сохраняем указатель на объект - реактор
 (setq stat-vlr-object b-vlr-object)

;Ставим в очередь выполнение функции modline
  (vla-SendCommand 
    (vla-get-ActiveDocument (vlax-get-acad-object)) 
    "(modline) ")

;Сваливаем из реактора
)
Вложения
Тип файла: dwg
DWG 2004
Линия.dwg (24.5 Кб, 1364 просмотров)
Тип файла: lsp Линия.lsp (1.8 Кб, 136 просмотров)
Supermax вне форума  
 
Автор темы   Непрочитано 28.11.2008, 22:31
#15
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Вся фишка заключается в том, что нельзя из реактора удалять все указатели на объекты, иначе он умрет. Вот поэтому и надо создавать временный элемент, чтобы он дал возможность выбросить из реактора элемент, требующий редакции.
Supermax вне форума  
 
Непрочитано 28.11.2008, 22:51
#16
Baldares


 
Регистрация: 17.10.2008
Саратов
Сообщений: 426


Supermax, ни фига не понятно.
А в какой момент, и где прописано, прицепка реактора к блоку?
Скопировал блок в другой файл, загрузил лисп, и не работает реактор.
А в оригинале, первый раз еще можно двигануть стрелку у блока, но при этом длина устанавливается принудительно в 500, а далее вообще не сместа.
Так где же цепляла реактора к блоку сидит?
Или тут глупые вопросы ни-ни.
Baldares вне форума  
 
Непрочитано 29.11.2008, 00:05
#17
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Supermax, даже если забыть про #16, ты постоянно создаешь "левый" объект. Ты, похоже, еще не "ловил" ошибку переполнения количества объектов...
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 29.11.2008, 09:46
#18
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Отвечаю сразу обоим.
Есть файл, в нем есть блок, на блок навешен реактор, реактор не в блоке, а в рисунке, поскольку он может следить за несколькими объектами. Копирование блока из файла в файл к копированию реактора не приводит! Его надо заново устанавливать.

Установка реактора пост #6
Код:
[Выделить все]
; Указываем на нужный нам объект:
(setq obj (vlax-ename->vla-object (car (entsel))))
;Устанавливаем на него реактор модификации 
(setq reactor1 (vlr-object-reactor (list obj) nil (list '(:VLR-modified . vlr-sdd22))))
;Делаем его постоянным
(vlr-pers reactor1)
Если открыть блок редактором блоков и добавить туда, или перенести, или все, что угодно, лишь бы осталось то наименование динамического свойства, которое в реакторе записано. Можно даже все стереть и заново нарисовать, но НАИМЕНОВАНИЕ свойства должно быть прежним (чтобы реактор мог его найти и установить заданное значение), то реактор от этого, с блока не исчезнет.

Временный объект, на то и временный, что он создается->устанавливается->...->снимается->удаляется. Это не блок и переполнения библиотеки не будет. Мой реактор всегда содержит только один элемент, и только при срабатывании в нем появляется второй ВРЕМЕННО! Если надо сделать реактор, следящий сразу за группой объектов, то там не надо делать временных объектов.
Kpblc, в лиспе каждая строчка подписана!
Supermax вне форума  
 
Автор темы   Непрочитано 29.11.2008, 14:48
#19
Supermax

Руководитель фирмы
 
Регистрация: 28.03.2007
Москва
Сообщений: 1,831
Отправить сообщение для Supermax с помощью Skype™


Есть один подводный камень. Не знаю как на других Автокадах, а у меня на 2007 он присутствует.

Если взять мой блок с прикрученным реактором и не растягивать его ручками, а залезть в пропертиес и там установить значение длинны линии цифрами, то блок начинает себя вести очень хитро. Ручка всегда возвращается на установленную длинну, а вот линия все удлинняется, и удлинняется (если ручку в сторону удлиннения перемещать), или укорачивается (если ручку перемещать внутрь). Явный баг Автокада, но если он у всех, его можно использовать.
Supermax вне форума  
 
Непрочитано 29.11.2008, 15:16
#20
Baldares


 
Регистрация: 17.10.2008
Саратов
Сообщений: 426


Да такаяже фишка. Акад 2008 MEP рус., акад 2009 рус.
И как енто будешь использовать?
Baldares вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > AutoLISP: Работа с реакторами



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
передача данных из AutoLisp в Excel Victorovich LISP 2 03.12.2011 22:28
Параметрическая библиотека в autoLISP joisegatoi LISP 8 18.06.2007 18:39
Autolisp и Visual Basic Книга Piton LISP 6 27.02.2006 09:54