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

ADN Club => AutoLisp / VisualLISP и DCL => Тема начата: Macondo от 18-10-2015, 02:11:59

Название: Параметры удалённого примитива.
Отправлено: Macondo от 18-10-2015, 02:11:59
В процессе изучения реакторов появилась задача отследить удаление определённых объектов (с расширенными данными) с чертежа.
Для тестирования был написан такой код:
Код - Auto/Visual Lisp [Выбрать]
  1. (defun object-reactors ( / )
  2.  (vl-load-com)
  3.  (vlr-remove-all)
  4.  (setq object-reactor (vlr-acdb-reactor nil '((:VLR-objectErased . object-erased)
  5.                                                                          (:VLR-objectUnerased . object-unerased))))
  6. )

Код - Auto/Visual Lisp [Выбрать]
  1. (defun object-erased (reactorcallback cname / )
  2. ;Если у удалённого примитива есть нужные расширенные данные, появляется сообщение:
  3.  (if (AND (assoc -3 (entget (cadr cname) '("myapp"))) (= (cdr (assoc 1000 (cdadr (assoc -3 (entget (cadr cname) '("myapp")))))) "myXdata"))
  4.       (alert "erased!")
  5.  )
  6.  (princ)
  7. )

Вскоре выяснилось, что хоть (cadr cname) и возвращает имя удалённого примитива, но (entget (cadr cname)) возвращает nil, потому что у удалённого примитива невозможно посмотреть свойства.

Какие тут есть хитрости, чтобы всё же сделать проверку свойств удалённого примитива без его восстановления и повторного удаления, на что потребуются ресурсы оперативной памяти и времени?
Название: Re: Параметры удалённого примитива.
Отправлено: Александр Ривилис от 18-10-2015, 12:06:46
Средствами lisp нельзя получить информацию о расширенных данных удалённого примитива. Поэтому я вижу два альтернативных способа:
1) восстанавливать примитив: (entdel en), получать информацию и удалять повторно.
ресурсы оперативной памяти не потребуются, т.к. при удалении примитива память не освобождается. Но нужно будет контролировать повторное попадание в реактор.
2) Написать функцию с использованием ObjectARX (C++) или AutoCAD .NET API (C#, VB.NET, ...) - в них можно работать с удалёнными примитивами.
Название: Re: Параметры удалённого примитива.
Отправлено: Macondo от 18-10-2015, 15:13:35
1) восстанавливать примитив: (entdel en), получать информацию и удалять повторно.
Бился-бился, пытаясь воплотить в жизнь это решение, а потом прочитал у Николая Полещука в книге:
Цитировать
"Объект, который стал источником события, не может быть модифицирован из функции действия, реагирующей на это событие".
Название: Re: Параметры удалённого примитива.
Отправлено: Алексей Кулик от 18-10-2015, 15:14:36
Я бы выполнял эти проверки перед удалением, если это возможно. Объектные реакторы стараюсь вообще не использовать - от них (судя по моему опыту) проблем больше, чем решений.
Название: Re: Параметры удалённого примитива.
Отправлено: Macondo от 18-10-2015, 15:36:33
Алексей Кулик, AcDb — это ведь не объектные реакторы, а ректоры базы чертежа, или ты не в этом смысле?
Я бы выполнял эти проверки перед удалением, если это возможно
Перед удалением тоже должно что-то сработать для запуска проверки. Что, если не реактор?
Название: Re: Параметры удалённого примитива.
Отправлено: Александр Ривилис от 18-10-2015, 15:52:35
Перед удалением тоже должно что-то сработать для запуска проверки. Что, если не реактор?
Теоретически должен сработать реактор :vlr-objectOpenedForModify
Бился-бился, пытаясь воплотить в жизнь это решение, а потом прочитал у Николая Полещука в книге:
Цитировать

    "Объект, который стал источником события, не может быть модифицирован из функции действия, реагирующей на это событие".
Отмечай в этом реакторе, а удаляй в командном реакторе (завершение команды: :vlr-commandEnded или :vlr-commandCancelled или :vlr-commandFailed)
Название: Re: Параметры удалённого примитива.
Отправлено: Александр Ривилис от 18-10-2015, 16:24:12
Вообще это выглядит как-то так (не проверял на ошибки в коде):
Код - Auto/Visual Lisp [Выбрать]
  1. (defun object-reactors ( / )
  2.    (vl-load-com)
  3.    (vlr-remove-all)
  4.    (setq __elist__ nil)
  5.    (setq object-reactor
  6.        (vlr-acdb-reactor nil '(
  7.           (:vlr-objectOpenedForModify . object-OpenedForModify)
  8.           (:VLR-objectErased . object-erased)
  9.        ))
  10.    )
  11. )
  12. (defun object-erased (reactorcallback cname / )
  13.    (if (and (eq (cdr (assoc -1 __elist__)) (cadr cname))
  14.             (= (cdr (assoc 1000 (cdadr (assoc -3 __elist__ '("myapp"))))) "myXdata"))
  15.       (alert "Erased my entity!!!")
  16.    )
  17. )
  18. (defun object-OpenedForModify (reactorcallback cname / )
  19.  (setq __elist__ (entget (cadr cname) '("myapp")))
  20.  (princ)
  21. )

P.S.: Проверил. Этот код не работает, т.к. и в событии OpenedForModify (entget) не работает.

P.S.S: В конце концов ты можешь в любой момент времени отобрать в список "свои примитивы" и поставить объектные реакторы на их удаление.
Название: Re: Параметры удалённого примитива.
Отправлено: Macondo от 21-10-2015, 23:45:32
В конце концов ты можешь в любой момент времени отобрать в список "свои примитивы" и поставить объектные реакторы на их удаление.
Можно при вставке "своих примитивов" сразу вешать на них объектные реакторы vlr-object-erased (и unerased), но при удалении вернётся только имя объекта. Свои же примитивы если и хранить списком, то списком Handle, который не меняется при переоткрытии чертежа. А при обработке события реакторы нельзя использовать (vla-get-Handle), т.к. она вернёт nil.
Название: Re: Параметры удалённого примитива.
Отправлено: Александр Ривилис от 21-10-2015, 23:52:17
но при удалении вернётся только имя объекта.
Вообще-то я думал, что тебя интересует сам факт удаления "твоего" примитива. Если же тебя интересуют и их свойства, то восстанавливай их в командном реакторе и получай их свойства. Ну или мигрируй на ObjectARX или .NET
Название: Re: Параметры удалённого примитива.
Отправлено: Дима_ от 22-10-2015, 01:13:48
Можно хранить в памяти ассоциативный список пар (ename_примитива . расширенные_данные) ну и соответственно следить за поддержанием его в актуальном состоянии - такой метод кстати в некоторых случаях является единственным и в .Net (и по моему и в ARX) - например при перемещении ручек примитива - так-же возвращается не "настоящий" указатель, а его копия.
Название: Re: Параметры удалённого примитива.
Отправлено: Macondo от 22-10-2015, 01:20:34
Вообще-то я думал, что тебя интересует сам факт удаления "твоего" примитива.
Так и есть. Но помимо самого факта удаления некоего примитива с расширенными данными важно понять, какой из них был удалён. А при удалении примитива от реактора мы получаем максимум его имя, а не указатель, что однозначно могло бы указать на примитив для осуществления неких внеших действий (например, удаление ссылки на объект во внешнем текстовом файле по указателю).
Ну или мигрируй на ObjectARX или .NET
В .NET есть возможность узнать свойства (в т.ч. указатель на объект, наличие расширенных данных) удалённого объекта и аналоги лисповских реакторов для этого?
Название: Re: Параметры удалённого примитива.
Отправлено: Александр Ривилис от 22-10-2015, 07:38:27
В .NET есть возможность узнать свойства (в т.ч. указатель на объект, наличие расширенных данных) удалённого объекта и аналоги лисповских реакторов для этого?
Если ты имеешь в виду метку (handle) примитива, то да. Реакторов в нём поболее чем в лиспе. Самое большое количество возможностей в ObjectARX.