Динамические блоки стали очень полезными элементами современного Автокада. Широкое применение динамических блоков значительно ускоряет процесс проектирования.
В этом уроке мы рассмотрим, как можно вставлять динамический блок и присваивать значения его атрибутам из LISP-программы. Для этого нам понадобятся материалы прошлых уроков.
Вначале мы создадим блоки куба с дополнительными данными при помощи программы, рассмотренной нами в уроке: «LISP. Создание блока».
Скачать программу Mp_kub3.lsp (Размер файла: 993 bytes)
Затем извлечем из блока дополнительные данные.
Вставим динамический блок, созданный нами в уроке: «Создание динамического блока», и внесем в него дополнительные данные из блока куба.
Скачать динамический блок (Размер файла: 30 kB)
И так приступим:
Запустите AutoCAD.
Откройте Редактор Visual LISP, набрав в командной строке VLIDE (или VLISP)
Откройте программу mp_kub3, созданную в уроке: «LISP. Создание блока». См. Рис. 1
Нажимаем кнопку «Загрузить активное окно редактора».
Затем на кнопку «Активизация AutoCAD».
Вводим в командной строке: mp_kub3 и нажмите <Enter>.
На запрос «Задайте длину стороны куба :» введите 300 и нажмите <Enter>
На запрос «Укажите базовую точку :» щелкните мышкой в рабочем окне Автокад.
Программа создаст блок куба с размерами сторон 300.
Повторно запустите программу (нажмите <Enter>).
На запрос «Задайте длину стороны куба :» введите 400 и нажмите <Enter>
На запрос «Укажите базовую точку :» щелкните мышкой в рабочем окне Автокад.
Программа создаст блок куба с размерами сторон 400.
В результате получим два куба, один со сторонами 300, другой 400. См. Рис. 2.
Вернемся в Редактор Visual LISP.
Создадим новый файл. Сохраним его под именем Udim.lsp.
Добавим в него строку для работы с функциями, входящими в расширение языка AutoLISP.
(vl-load-com) - загружает функции расширения
Далее при помощи функции entsel попросим пользователя выбрать блок:
(entsel "Выберите блок: ")
Функция entsel возвращает имя указанного блока и координату точки указания.
При помощи функции car оставляем, только имя указанного блока:
(car (entsel "Выберите блок: "))
Функция car извлекает первый элемент из списка.
При помощи функции setq сохраняем имя блока в переменной obj:
(setq obj (car (entsel "Выберите блок: ")))
Далее преобразуем выбранный блок в vla-объект:
(setq vla_obj (vlax-ename->vla-object obj))
Имя vla-объекта сохраняем в переменной vla_obj.
Теперь мы можем извлечь дополнительные данные, которые ранее добавляли к блоку.
Для этого используем функцию vlax-ldata-get:
(setq V (vlax-ldata-get vla_obj "obem")) – извлекает данные из VLA-объекта vla_obj по коду "obem", и сохраняет их в переменной V.
(setq po (vlax-ldata-get vla_obj "tochka")) – извлекает данные из VLA-объекта vla_obj по коду "tochka", и сохраняет их в переменной po.
Выделите весь текст и нажмите на кнопку «Загрузить выделенный фрагмент». См. Рис. 3.
На запрос «Выберите блок :» — укажите один из двух блоков.
Чтобы посмотреть значения переменных.
Выделите переменную V и нажмите на кнопку «Добавить контрольное значение».
Затем, выделите переменную ро и снова нажмите на кнопку «Добавить контрольное значение». Откроется окно «Контрольное значение», где можно посмотреть, чему равны переменные. См. Рис. 4.
Мы видим, что нам удалось получить данные, которые ранние мы добавляли в блок.
Давайте еще извлечем имя блока.
При помощи функции entget получим список с характеристиками примитива (блока).
Откройте консоль Visual LISP.
Добавьте строку (entget obj).
Выделите ее и нажмите на кнопку «Загрузить выделенный фрагмент». См. Рис. 5.
Функция вернет список:
((-1 . <Имя объекта: 7ed146c8>) (0 . «INSERT») (5 . «251») (102 . «{ACAD_XDICTIONARY») (360 . < Имя объекта: 7ed146d0>) (102 . «}») (330 . < Имя объекта: 7ed12cf8>) (100 . «AcDbEntity») (67 . 0) (410 . «Model») (8 . «0») (100 . «AcDbBlockReference») (2 . «kub400») (10 1485.09 652.573 0.0) (41 . 1.0) (42 . 1.0) (43 . 1.0) (50 . 0.0) (70 . 0) (71 . 0) (44 . 0.0) (45 . 0.0) (210 0.0 0.0 1.0))
Из этого списка нам нужно извлечь имя блока. Мы видим, что DXF-код имени блока = 2.
Используем для этого функцию assoc .
Функция assoc применяется к сложному списку, каждый элемент которого начинается с DXF-кода. Именно по этому коду функция assoc и извлекает элемент из списка.
(assoc 2 (entget obj))
2 - DXF-код имени блока. (entget obj) — список с данными блока.
Их списка будет извлечен элемент DXF-кодом 2:
Функция вернет следующее значение:
(2 . "kub400")
Чтобы оставить только имя блока, применим функцию cdr.
(cdr (assoc 2 (entget obj)))
Функция cdr – возвращает список без первого элемента.
Сохраним имя блока в переменной bl_name.
(setq bl_name (cdr (assoc 2 (entget obj))))
Добавьте эту строку, выделите ее, загрузите выделенный фрагмент. В окне консоль Visual LISP появится возвращаемое значение – имя блока. См. Рис. 6.
Все необходимые данные мы получили, теперь можно вставлять наш динамический блок “Vyn”.
Я напомню, что предыдущем уроке («Создание динамического блока») мы сохранили его в папке MyLisp: (D:\MyLisp\Vyn.dwg).
Если эта папка добавлена у Вас в пути поддержки Автокад. В программе достаточно использовать имя блока “Vyn”.
Если нет, то нужно использовать полный путь к файлу
“D:\MyLisp\Vyn.dwg”.
Как добавить папку в пути поддержки Автокад, показано в уроке «Пример программы LISP с диалоговым окном».
Вставляем динамический блок:
(command "_insert" "Vyn" po 1 1 0 bl_name V)
"_insert" – стандартная команда Автокад вставки блока; "Vyn" – имя вставляемого блока; (Если папка, в которой находится блок не прописана вспомогательных путях Автокад, в качестве имя нужно указать полный путь к файлу “D:\MyLisp\Vyn.dwg”) рo – базовая точка вставки блока; 1 – масштабный коэффициент по оси X; 1 – масштабный коэффициент по оси Y; 0 – угол поворота блока в радианах; bl_name – значение верхнего атрибута; V – значение нижнего атрибута;
Добавляем эту строчку и преобразуем нашу программу в пользовательскую функцию defun
(defun c:Udum (/) <наша программа> ) ; end_defun
В результате получим. См.Рис. 7.
Загружаем активное окно редактора.
Переходим в Автокад.
В командной строке вводим Udim и нажимаем <Enter>.
На запрос «Выберите блок :» — укажите один из двух блоков.
Повторите команду (нажмите <Enter>).
На запрос «Выберите блок :» — укажите второй блок.
Программа построит две выноски. См. Рис. 8.
Мы видим, что у блока kub300 базовая точка не попала в цент верхней грани. Это произошло потому, что в момент вставки блока сработала привязка «середина отрезка». Поэтому когда вставляется блок привязки нужно отключить:
(setq osm (getvar "osmode")) – запоминаем привязки пользователя (setvar "osmode" 0) – отключаем привязки
Вставляем блок.
(setvar "osmode" osm) – возвращаем привязки пользователя.
Кроме этого давайте сделаем так, чтобы наша программа бесконечное количество раз просила выбрать блок, до тех пор, пока мы сами не прервем ее нажав <Esc>.
Для этого, добавим бесконечный цикл.
(while Т <выражения> ) :end while.
(более подробно об этом рассказано в уроке: «Пример AutoLISP программы: Сумма длин отрезков»)
Если пользователь при выборе блока промахнется и щелкнет на пустом месте, программа прервет свою работу, в командной строке появится надпись:
; ошибка: неверный тип аргумента: lentityp nil
Поэтому добавляем условие, которое будет проверять, чтобы переменная obj не равнялась nil.
(if (not (= obj nil)) (progn <наши выражения> ) ;end progn ) ; end if
(более подробно об этом рассказано в уроке: «Пример AutoLISP программы: Сумма длин отрезков»)
В результате получим см. рис. 9.
Проверяем работу программы.
Удаляем динамические блоки.
Загружаем активное окно редактора.
Переходим в Автокад.
В командной строке вводим Udim и нажимаем <Enter>.
На запрос «Выберите блок :» — специально пощелкайте мимо блока. Программа не прерывается. Укажите один блок.
На следующий запрос «Выберите блок :» — выберите второй блок.
На следующий запрос – нажмите <Esc>.
Программа построит две выноски. См. Рис. 10
Мы видим, что полки у динамических блоков немного коротковаты. К тому же полку у блока kub400 не помешало бы немного поднять. Поскольку это динамические блоки, мы без особого труда можем сделать это вручную, но все таки хочется, чтобы это делала программа. Этим мы займемся в следующем уроке.
В заключение добавляем локальные переменные в список временных переменных функции defun. См. Рис. 11.
Код программы:
(defun c:Udim (/ obj vla_obj V po bl_name osm) (vl-load-com) ; загружаем функции расширения (while T (setq obj (car (entsel "\nВыберите блок: "))) (if (not (= obj nil)) (progn (setq vla_obj (vlax-ename->vla-object obj)) ; переводим в vla-object (setq V (vlax-ldata-get vla_obj "obem")) ; объем (setq po (vlax-ldata-get vla_obj "tochka")) ; координаты центра (setq bl_name (cdr (assoc 2 (entget obj)))) ; имя блока (setq osm (getvar "osmode")) ; запоминаем привязки пользователя (setvar "osmode" 0) ; отключаем привязки (command "_insert" "Vyn" po 1 1 0 bl_name V) ; вставка блока (setvar "osmode" osm) ; возвращает привязки пользователя );end progn ); end if ); end while ); end_defun
Скачать программу Udim.lsp (Размер файла: 538 bytes)
На этом наш урок окончен.
В следующем уроке мы рассмотрим, как из LISP-программы изменять геометрические характеристики динамического блока.
Пишите в комментариях:
Трудно ли было выполнить этот урок?
Была ли для Вас полезной информация, данная в этом уроке?
На какие вопросы программирования, Вы хотели бы, увидит ответы в следующих уроках?
Я с удовольствием отвечу на ваши вопросы.
Если вы хотите получать новости с моего сайта. Оформляйте подписку.
До новых встреч.
«Автор: Михаил Орлов»
Офигенно!!!!!
Добрый день!
Как можно реализовать такой вариант выноски
1. Атрибут блока : если нет или nil то пункт 2
2. Видимость блока: если нет или nil то пункт 3
3. Имя блока : effectivename
Добрый день, огромное спасибо за ваши уроки, могли бы вы подсказать как извлечь значения атрибутов блока, и вставить их в мультивыноску.
Я не знаю, как у Вас сделана мультивыноска.
Если как дим. блок «Vyn», то
Спасибо, это тоже пригодиться, а если речь идет о _.mleader, намного усложниться код? Нужно ли полностью программно создавать мультивыноску включая стиль или можно обойтись как то проще?
Можно полностью программно создавать стиль мультивыноски и сделать его текущим или использовать стиль текущий на данный момент.
Отлично, то что надо, единственное не получается добавить второй атрибут в mleader под полку, аналогично тому как это выполнялось в блоке-выноске «vyn», спасибо за внимание
У меня вставка блока работает не совсем корректно. Блок вставляется а атрибуты нет. Вылазит диалоговое окно, где меня просят ввести имена атрибутов Если посмотреть Окно команд (F2), то видно, что Autocad ругается на то, что «имя блока» — это не известная команда. То есть автокад принял имя блока за команду, а не вставил это имя в атрибут.
Что я сделал не так?
На запрос: Выберите блок: Вы должны указать на блок созданный программой mp_kub3.lsp. Именно из него программа считывает значения атрибутов. Если не получиться разобраться пришлите мне на почту: acadprog@gmail.com Вашу программу и файл автокада с кубом созданным программой mp_kub3.lsp. Я посмотрю и тогда отвечу.
Блок можно вставить через vla-функции:
Вместо строки:
Можно поставить следующие:
Попробуйте, может так будет работать.
У меня та же проблема! Пишу программу основываясь на ваших уроках. Делаю аналогичную функцию. Атрибуты не вставляются.
Вот кусок кода
(command "_insert" "Po_Trav"
(setq po (getpoint))
1 1 0
pk tip trav_pr trav_fa
)
Переменные pk tip trav_pr trav_fa хочу использовать как аргументы. Значения их соответственно по порядку «100» «По1» «123» «123.008».
Автокад пишет
Команда: ISP_TR
_insert Имя блока или [?] : magic/Po_Trav
Единицы: Миллиметры
Точка вставки или [Базовая точка/Масштаб/X/Y/Z/ПОворот]:
Укажите точку вставки:
Введите масштаб по оси X, укажите второй угол или [Угол/XYZ] : 1 Масштаб по оси Y : 1
Угол поворота : 0
Команда: 100
Команда: По1 Неизвестная команда "ПО1". Для вызова справки нажмите F1.
Команда: 123
Команда: 122.999483
Не знаю где ошибка =(
Пришлите программу и блок на почту: acadprog@gmail.com
Строка отключает вывод диалогового окна атрибутов при вставке блока:
Чтобы временно его отключить:
В конце программы снова включаем:
Спасибо! Сразу стало всё работать =)
Хотел бы дополнить. Если ATTREQ=0 то работать тоже не будет. Надо добавлять еще и это
(setq attr (getvar "ATTREQ"))
(setvar "ATTREQ" 1)
В конце программы снова включаем:
(setvar "ATTREQ" attr)
Спасибо за код и подробное описание! Но никак не могу решить свою проблему. Необходимо извлечь из статического блока данные, записанные во вхождении в виде однострочного текста через пробел например «12 16 а8 гпр», количество переменных в тексте всегда разное. Прошу помощи так как попал в тупик
В каком виде ваши данные хранятся в блоке (атрибут или доп. данные vla-объекта)? Вы не можете их извлечь или не можете разделить строку?
Блок уже создан и требуется из него извлечь данные хранящиеся в однострочном тексте. В доп данных vla объекта их нет и атрибутов к блоку нет.
Михаил, добрый день!
Зачем добавлять в пользовательскую функцию «defun» локальные переменные, если она и без них работает?
С уважением,
Валентина
В AutoLISP по умолчанию все создаваемые переменные глобальные, т.е. они будут храниться в памяти программы AutoCAD, после завершения команды Udim (пока Вы не закроете Автокад). Чтобы сделать их локальными (временными), их добавляют в описание функции DEFUN. И тогда после завершения команды Udim, они не болтаются в памяти AutoCAD.
Добрый день. Подскажите, как извлечь из dxf кода имя динамического блока
Но иногда? в каких-то версиях Автокада имена блоков в dxf-кодах слетают и Вы можете получить вместо имени что-то вроде «*U184»
Надежней получить имя через vla-объект:
Благодарю
Добрый день Михаил!
В Уроке 13 «ВСТАВКА ДИНАМИЧЕСКОГО БЛОКА ИЗ LISP-ПРОГРАММЫ» при вставке динамического блока строка (command «_insert» «Vyn» po 1 1 0 bl_name V ) ; вставка блока выводилось окно ред атрибутов и после ОК программа воспринимала данные (bl_name и V) как неизвестные команды и прерывалась пока я не изменил системную переменную ATTDIA на 0
Извините Михаил! Ответ нашел в Ваших комментариях….
Возможна реализация такой выноски
1. Атрибут блока: если нет или nil пункт 2
2. Видимость блока: если нет или nil пункт 3
3. Имя блока: EffectiveName
Михаил, приветствую! огромная благодарность Вам за Ваши уроки! пытаюсь по ним освоить программирование lisp. Есть вопрос: у меня создан динамический блок с параметром видимости. на первом этапе изучения lisp я хочу создать код для вставки этого блока в чертеж с выбором видимости. То есть:
1) запустил команду->
2) указал точку вставки->
3) выбрал видимость в диалоговом окне
с пунктами 1 и 2 проблем не возникло, но каким образом должен выглядеть код программы чтобы реализовать пункт 3
заранее благодарю!
Для пункта 3 нужно создать диалоговое окно DCL. Оно у Вас создано? Про диалоговые окно можно прочитать здесь: https://acad-prog.ru/dialogovoe-okno-avtokad/ и https://acad-prog.ru/dialogovoe_okno/