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

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

Название: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 12-10-2015, 18:25:11
Всем привет!
Интересует, как можно программно интерактивно ("на курсоре") перемещать текст атрибута блока. Если делать это вручную, вызывается команда **stretch**, причём если запустить саму команду _stretch, то она будет перемещать и атрибут, и сам блок. _Move аналогичен. Есть ли какие-то работающие варианты подобной реализации?
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 12-10-2015, 19:24:33
Есть несколько вариантов:
1) Стандартная команда _-ATTEDIT
2) С использование функции (grread) считывать координаты курсора и перемещать атрибут.
3) С использованием моей утилиты dyndraw: http://www.maestrogroup.com.ua/support/dyndraw.zip
(там есть примеры не связанные с атрибутами, но идея должна быть ясна)
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 12-10-2015, 20:13:43
1) Стандартная команда _-ATTEDIT
Спасибо! Неплохо справляется с задачей в виде
(vl-cmdf "_-attedit" "" "" "" "" atr "_P" pause "")Правда, без "резиновой нити" (не так важно). Кроме того, на месте первоначальной точки возникает огромное перекрестие. Может, за его отображение отвечает какая-то системная переменная?
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 12-10-2015, 20:58:14
Кроме того, на месте первоначальной точки возникает огромное перекрестие. Может, за его отображение отвечает какая-то системная переменная?
Насколько я помню возможности управлять этим перекрестьем нет.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 12-10-2015, 21:48:21
Есть еще неотмеченный мной вариант. Сделать дубликат атрибута в виде текста (или мультитекста - зависит от многострочности атрибута) и таскать его. Например командой _MOVE или функцией (acet-ss-drag-move). После завершения "таскания" дубликат стереть, а атрибут перетащить (поменять точку вставку и точку выравнивания).
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Дима_ от 12-10-2015, 21:48:37
+ к сказанному - при установленных Express Tools становится доступна лисп функция acet-ss-drag-move ...
Код - Auto/Visual Lisp [Выбрать]
  1. (acet-ss-drag-move (ssget) (getpoint "\nБазовая ") "\nДвигай... " nil 2)
p.s. ops опоздал
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 12-10-2015, 21:51:08
+ к сказанному - при установленных Express Tools становится доступна лисп функция acet-ss-drag-move ...
А тут ты попался! :) Будет двигаться весь блок. Атрибут таким образом ты не подвинешь.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Дима_ от 12-10-2015, 21:52:35
Не - не попался - я для примера как подвинуть "вися" на курсоре - понятно дело (ну мне по крайней мере), что к блоку так не пойдет - нужна предварительная работа.
Кстати у меня сейчас expressoв нету - а если в набор добавить только (entnext...) атрибута - подвинет?
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 12-10-2015, 21:53:02
Сделать дубликат атрибута в виде текста (или мультитекста - зависит от многострочности атрибута) и таскать его.
Кстати, тоже хороший вариант! Я не уточнил в начале: если данное действие требуется совершать во время вставки блока с атрибутом, то, может, есть встроенные решения? Не нашёл свойства атрибута вроде "указание точки вставки" при вставке блока.
при установленных Express Tools становится доступна лисп функция
Не подойдёт, поскольку Express Tools может быть и не установлен, нужны простые решения!
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 12-10-2015, 22:00:13
Я не уточнил в начале: если данное действие требуется совершать во время вставки блока с атрибутом, то, может, есть встроенные решения?
Это как? Если вставлять командой _INSERT, то положение атрибутов во время вставки изменить нельзя. Управлять запросом вставки атрибутов можно при помощи системных переменных ATTREQ и ATTDIA.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 12-10-2015, 22:33:48
Вариант с текстом показался самым естественным для отображения (если бы не перекрестье, то подошёл бы и первый).
Вот такой код получился (при наличии значения переменной model_space):
Код - Auto/Visual Lisp [Выбрать]
  1. (vl-catch-all-apply 'vl-cmdf (list "_-insert" block_name "_PX" block_dimension "_PY" block_dimension pause block_dimension block_dimension pause)); вставка блока
  2.         (foreach item (vlax-safearray->list (vlax-variant-value (vla-GetAttributes (vlax-ename->vla-object (entlast)))))
  3.           (if (AND (= (vla-get-tagstring item) "POZ") (eq (vla-get-textstring item) "")); ищем пустой атрибут с нужным тегом
  4.             (progn
  5.               (vla-put-textstring item position); добавление текста атрибута из переменной position
  6.               (vla-AddText model_space (vla-get-textstring item) (vla-get-InsertionPoint item) (vla-get-Height item)); создание временного текста
  7.               (setq temp_text (entlast))
  8.               (vl-catch-all-apply 'vl-cmdf (list "_move" (entlast) "" (vlax-safearray->list (vlax-variant-value (vla-get-InsertionPoint item))) pause))
  9.               (vla-put-InsertionPoint item (vlax-3d-point (getvar "LASTPOINT"))); изменение положения текста атрибута
  10.               (entdel temp_text); удаление временного текста
  11.             )
  12.           )
  13.         )
  14.  
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 12-10-2015, 23:13:14
Обрати внимание на правила форматирования кодов у нас на форуме (у меня в подписи).
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Алексей Кулик от 13-10-2015, 21:56:17
Н-да, пока я был на AURU2015, тут, оказывается, такие интересные штуки творились :)
Несколько вопросов по коду:
1. А если пользователь в ответ на запрос нажмет правую кнопку или Esc?
2. Почему создается текст, а удаляется примитив, который был перед ним? Там же может быть все что угодно...
3. Не учитывается вариант многострочного атрибута
4. Не учитывается вариант установленного выравнивания атрибута
5. Не учитываются варианты заблокированных / замороженных слоев

Я бы код писал по другим принципам:
- отдельная универсальная функция вставки блока. Используется при вставке block_name
- получение указателя на нужный атрибут
- создание анонимного блока, внутри которого только однострочный / многострочный текст
- используя ту самую универсальную функцию, вставляем анонимный блок по запросу пользователя. Если блок был вставлен, то получаем у него точку вставки
- полученному атрибуту устанавливаем точку вставки и / или выравнивания атрибута
- удаление вставки анонимного блока.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 14-10-2015, 03:28:54
1. А если пользователь в ответ на запрос нажмет правую кнопку или Esc?
2. Почему создается текст, а удаляется примитив, который был перед ним? Там же может быть все что угодно...
3. Не учитывается вариант многострочного атрибута
4. Не учитывается вариант установленного выравнивания атрибута
5. Не учитываются варианты заблокированных / замороженных слоев
1. Если пользователь прерывает команду, атрибут останется на месте по умолчанию. Этот цикл обрамлён в другой цикл:
Код - Auto/Visual Lisp [Выбрать]
  1. (while (vl-catch-all-apply 'vl-cmdf (list "_-insert" block_name "_PX" block_dimension "_PY" block_dimension pause block_dimension block_dimension pause))
  2.   (foreach ... )
  3. )
2. Создаётся текст, затем он же заносится в переменную temp_text, а потом он удаляется через (entdel temp_text).
3,4. Атрибут будет задаваться в окне и не сможет быть многострочным или с другим выравниванием.
5. Верное замечание, нужно будет написать функцию, которая бы размораживала и разблокировала слой:
Код - Auto/Visual Lisp [Выбрать]
  1. (defun unlock-unfreeze-layers  (layer_name)
  2.   (if (= (vla-get-Freeze (vla-item (vla-get-layers actdoc) layer_name)) :vlax-true)
  3.     (vla-put-Freeze (vla-item (vla-get-layers actdoc) layer_name) :vlax-false)
  4.   )
  5.   (if (= (vla-get-Lock (vla-item (vla-get-layers actdoc) layer_name)) :vlax-true)
  6.     (vla-put-Lock (vla-item (vla-get-layers actdoc) layer_name) :vlax-false)
  7.   )
  8. )
- отдельная универсальная функция вставки блока. Используется при вставке block_name
Непосредственно для вставки блока используется одна команда (insert), тем более если она в условии цикла, а сразу после while идёт добавление слоя-цвета, то функцию применять (мне кажется) не очень удобно.
Кстати, как считаешь, можно ли в функцию-обработчик завершения программы, где идёт восстановление системных переменных, дописать PURGE all? Если идёт вставка блоков, когда каждый блок находится в отдельном файле (command "_insert" (strcat block_name ".dwg") nil), то потом во "Вставке" остаётся мусор с названиями файлов.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 14-10-2015, 13:04:58
2. Создаётся текст, затем он же заносится в переменную temp_text, а потом он удаляется через (entdel temp_text).
В том виде, в котором ты выложил код, происходит совсем другое:
1) Ты сначала получаешь последний примитив, а затем создаешь новый текст:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq temp_text (entlast))
  2. (vla-AddText model_space (vla-get-textstring item) (vla-get-InsertionPoint item) (vla-get-Height item)); создание временного текста
2) После выполнения работы ты удаляешь  temp_text, что не есть твой временный текст

 
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 14-10-2015, 13:30:08
В том виде, в котором ты выложил код, происходит совсем другое
Не обратил внимание: разместил здесь код с ошибкой, а у себя проверял с нормальной последовательностью.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 14-10-2015, 13:49:22
Не обратил внимание: разместил здесь код с ошибкой, а у себя проверял с нормальной последовательностью.
Исправь тогда, пожалуйста, и здесь тоже свой код на рабочий.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Алексей Кулик от 14-10-2015, 15:20:35
Создаётся текст, затем он же заносится в переменную temp_text, а потом он удаляется через (entdel temp_text).
Я вижу другое: сначала (setq temp_text (entlast)), потом создается текст.
Атрибут будет задаваться в окне и не сможет быть многострочным или с другим выравниванием.
Что и как показывается в окне - дело десятое. Сам атрибут может иметь признак многострочности. Соответственно обработка для него будет немного другой.
Кстати, как считаешь, можно ли в функцию-обработчик завершения программы, где идёт восстановление системных переменных, дописать PURGE all? Если идёт вставка блоков, когда каждый блок находится в отдельном файле (command "_insert" (strcat block_name ".dwg") nil), то потом во "Вставке" остаётся мусор с названиями файлов.
Я делал не так: через ObjectDBX открывается "библиотечный файл", и оттуда берется описание блока. Копирование через CoyObjects. В результате мусора - минимум.
Анонимные блоки, не имеющие вхождений, автоматически уничтожаются при закрытии файла (по-моему, сохранение их не убивает). Так что при нормальном подходе код, скорее всего, будет значительно больше и сложнее, но зато в файле dwg не будет ничего лишнего.
P.S. Я совсем упустил из виду вариант работы не в мировой системе координат... У тебя нигде не выполняется преобразование (ни координат, ни нормалей) - так и должно быть? Или возможны варианты?
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Алексей Кулик от 14-10-2015, 15:20:58
Пока набивал ответ и бегал по начальству, уже ответы появились ;)
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 14-10-2015, 16:02:09
Я совсем упустил из виду вариант работы не в мировой системе координат... У тебя нигде не выполняется преобразование (ни координат, ни нормалей) - так и должно быть? Или возможны варианты?
Я про различные системы даже не подумал. Как делать правильно?
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 14-10-2015, 16:11:13
Я про различные системы даже не подумал. Как делать правильно?
Изучай функцию (trans). В большинстве случаев тебе понадобится преобразование ПСК->МСК и МСК->ПСК, т.е.
Код - Auto/Visual Lisp [Выбрать]
  1. (trans p 1 0) ; ПСК->МСК (UCS->WCS)
  2. (trans p 0 1) ; МСК->ПСК (WCS->UCS)
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Алексей Кулик от 14-10-2015, 16:13:34
Нну, по идее надо помнить, что при вставке некоторых примитивов (блоки, атрибуты, тексты, полилинии...) координаты для них могут (в зависимости от метода обработки и получения) показываться как в мировой системе координат, так и в системе координат объекта. При этом vla-функции, как правило, работают именно с мировой системой, а ename (насколько я помню) - с системой координат объекта. Поэтому постоянно приходится использовать функцию trans для преобразования одних координат в другие. При этом запросы точек getpoint вообще возвращает координаты в экранной системе (если не ошибаюсь). (getvar "laspoint") в какой системе вернет значения - не знаю, надо тестировать.
Сейчас точно не помню, но, по-моему, vla-get-insertionpoint для блока, текста и атрибута возвращают координаты в WSC. Надо проверять, а сейчас времени, к сожалению, нет.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Александр Ривилис от 14-10-2015, 17:03:26
При этом запросы точек getpoint вообще возвращает координаты в экранной системе (если не ошибаюсь).
В ПСК (UCS)
(getvar "laspoint") в какой системе вернет значения - не знаю, надо тестировать.
В ПСК (UCS)
Сейчас точно не помню, но, по-моему, vla-get-insertionpoint для блока, текста и атрибута возвращают координаты в WSC.
В МСК (WCS)
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 12-03-2016, 15:20:13
Появилась неожиданная проблема в версиях 2015-2016:
Код - Auto/Visual Lisp [Выбрать]
  1. (while
  2.    (vl-catch-all-apply 'vl-cmdf (list "_-insert" block_name "_PX" 1"_PY" 1 pause 1 1 pause))
  3. ...
  4. )
Этот код в более ранних версиях AutoCAD выдавал при прерывании на Esc nil, что препятствовало дальнейшему выполнению кода ниже. А в 2015-2016 почему-то возвращается T.

Как с этим бороться?  :-\
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Алексей Кулик от 12-03-2016, 15:58:09
А если попробовать заменить vl-cmdf на command или command-s (с проверкой entlast)?
P.S. К сожалению, сейчас не могу предложить ничего иного. Если найду время - попробую что-нибудь придумать.
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Macondo от 12-03-2016, 16:45:11
А если попробовать заменить vl-cmdf на command или command-s
Они в любом случае (при выполнении и прерывании) выдадут nil, а vl-catch-all-apply при прерывании ошибку не почувствует.
с проверкой entlast
Спасибо за совет! Вроде, помогла такая форма:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq entl_entity (entlast)); Последний вставленный примитив
  2. (if entl_entity
  3.   (progn
  4.     (vl-catch-all-apply 'vl-cmdf (list "_-insert" block_name pause 1 1 pause))
  5.     (if (eq entl_entity (entlast)) nil T); Если после insert последний примитив изменился (вставка удалась), возвращаем Т
  6.   );progn
  7.   (progn
  8.     (vl-catch-all-apply 'vl-cmdf (list "_-insert" block_name pause 1 1 pause))
  9.     (if (entlast) T nil); Если это был первый вставленный на чертеже блок, и вставка удалась (появился entlast), возвращаем Т
  10.   );progn
  11. );if
Название: Re: Интерактивное перемещение текста атрибута блока
Отправлено: Алексей Кулик от 12-03-2016, 21:45:13
Сугубо ИМХО: а зачем лишние if? Может быть (код не проверял!) сработает и такая конструкция:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq entl_entity (entlast)) ; Последний вставленный примитив
  2. (if entl_entity
  3.   (progn (vl-catch-all-apply 'vl-cmdf (list "_-insert" block_name pause 1 1 pause))
  4.          (eq entl_entity (entlast))
  5.          ) ;_ end of progn
  6.   (progn (vl-catch-all-apply 'vl-cmdf (list "_-insert" block_name pause 1 1 pause)) (entlast))
  7.   ) ;_ end of if