Урок 13. Вставка динамического блока из LISP-программы.

Динамические блоки стали очень полезными элементами современного Автокада. Широкое применение динамических блоков значительно ускоряет процесс проектирования.

В этом уроке мы рассмотрим, как можно вставлять динамический блок и присваивать значения его атрибутам из LISP-программы. Для этого нам понадобятся материалы прошлых уроков. 

Вначале мы создадим блоки куба с дополнительными данными при помощи программы, рассмотренной нами в уроке: «LISP. Создание блока».

 Скачать программу Mp_kub3.lsp Скачать программу Mp_kub3.lsp (Размер файла: 993 bytes)

Затем извлечем из блока дополнительные данные.

Вставим динамический блок, созданный нами в уроке: «Создание динамического блока», и внесем в него дополнительные данные из блока куба.

 Скачать динамический блок Скачать динамический блок (Размер файла: 30 kB)

И так приступим:

Запустите AutoCAD.

Откройте Редактор Visual LISP, набрав в командной строке VLIDE (или VLISP)

Откройте программу mp_kub3, созданную в уроке: «LISP. Создание блока». См. Рис. 1

LISP. Динамический блок.

Рис. 1.   Программа mp_kub3.

Нажимаем кнопку «Загрузить активное окно редактора».

Затем на кнопку «Активизация AutoCAD».

Вводим в командной строке: mp_kub3 и нажмите <Enter>.

На запрос «Задайте длину стороны куба :» введите 300 и нажмите <Enter>

На запрос «Укажите базовую точку :» щелкните мышкой в рабочем окне Автокад.

Программа создаст блок куба с размерами сторон 300.

Повторно запустите программу (нажмите <Enter>).

На запрос «Задайте длину стороны куба :» введите 400 и нажмите <Enter>

На запрос «Укажите базовую точку :» щелкните мышкой в рабочем окне Автокад.

Программа создаст блок куба с размерами сторон 400.

В результате получим два куба, один со сторонами 300, другой 400. См. Рис. 2.

LISP. Динамический блок.

Рис. 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.

LISP. Динамический блок.

Рис. 3.   Извлекаем данные из VLA-объекта.

На запрос «Выберите блок :» — укажите один из двух блоков.

Чтобы посмотреть значения переменных.

Выделите переменную V и нажмите на кнопку «Добавить контрольное значение».

Затем, выделите переменную ро и снова нажмите на кнопку «Добавить контрольное значение». Откроется окно «Контрольное значение», где можно посмотреть, чему равны переменные. См. Рис. 4.

LISP. Динамический блок.

Рис. 4.  Значения переменных.

Мы видим, что нам удалось получить данные, которые ранние мы добавляли в блок.

Давайте еще извлечем имя блока.

При помощи функции entget получим список с характеристиками примитива (блока).

Откройте консоль Visual LISP.

Добавьте строку (entget obj).

Выделите ее и нажмите на кнопку «Загрузить выделенный фрагмент». См. Рис. 5.

LISP. Динамический блок.

Рис. 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.

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.

LISP. Динамический блок.

Рис. 7.  Вставляем динамический блок.

Загружаем активное окно редактора.

Переходим в Автокад.

В командной строке вводим Udim и нажимаем <Enter>.

На запрос «Выберите блок :» — укажите один из двух блоков.

Повторите команду (нажмите <Enter>).

На запрос «Выберите блок :» — укажите второй блок.

Программа построит две выноски. См. Рис. 8.

LISP. Динамический блок.

Рис. 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.

LISP. Динамический блок.

Рис. 9.  Добавляем строчки.

Проверяем работу программы.

Удаляем динамические блоки.

Загружаем активное окно редактора.

Переходим в Автокад.

В командной строке вводим Udim и нажимаем <Enter>.

На запрос «Выберите блок :» — специально пощелкайте мимо блока. Программа не прерывается. Укажите один блок.

На следующий запрос «Выберите блок :» — выберите второй блок.

На следующий запрос – нажмите <Esc>.

Программа построит две выноски. См. Рис. 10

LISP. Динамический блок.

Рис. 10.   Выноски.

Мы видим, что полки у динамических блоков немного коротковаты. К тому же полку у блока kub400 не помешало бы немного поднять. Поскольку это динамические блоки, мы без особого труда можем сделать это вручную, но все таки хочется, чтобы это делала программа. Этим мы займемся в следующем уроке.

В заключение добавляем  локальные переменные в список временных переменных функции defun. См. Рис. 11.

LISP. Динамический блок.

Рис. 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 Скачать программу Udim.lsp (Размер файла: 538 bytes)

На этом наш урок окончен.

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

Пишите в комментариях:

Трудно ли было выполнить этот урок?

Была ли для Вас полезной информация, данная в этом уроке?

На какие вопросы программирования, Вы хотели бы, увидит ответы в следующих уроках?

Я с удовольствием отвечу на ваши вопросы.

Если вы хотите получать новости с моего сайта. Оформляйте подписку.

До новых встреч.

 «Автор: Михаил Орлов»

Google

Также на эту тему Вы можете почитать:

30 комментарии на “Урок 13. Вставка динамического блока из LISP-программы.

    • Александр 20.09.2019 10:29

      Добрый день!
      Как можно реализовать такой вариант выноски
      1. Атрибут блока : если нет или nil то пункт 2
      2. Видимость блока: если нет или nil то пункт 3
      3. Имя блока : effectivename

  1. Антон 22.09.2014 16:34

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

    • Михаил Орлов 23.09.2014 07:30
      (setq obj (car (entsel "\nВыберите блок: ")))    ;блок с атрибутами
      (setq at1 (entget (entnext obj)))  ;извлекаем список первого атрибута
      (setq at1_text (cdr (assoc 1 at1)))         ; читаем значения атрибута
      (setq at2 (entget (entnext (entnext obj)))) ; список второго атрибута
      (setq at2_text (cdr (assoc 1 at2)))         ; читаем значения атрибута

      Я не знаю, как у Вас сделана мультивыноска.
      Если как дим. блок «Vyn», то

      (command "_insert" "Vyn" po 1 1 0 at1_text at2_text)    ; вставка блока
  2. Антон 23.09.2014 17:32

    Спасибо, это тоже пригодиться, а если речь идет о _.mleader, намного усложниться код? Нужно ли полностью программно создавать мультивыноску включая стиль или можно обойтись как то проще?

    • Михаил Орлов 25.09.2014 10:11
      (setq obj (car (entsel "\nВыберите блок: "))) ;просим выбрать блок
      (setq at1 (entget (entnext obj))) ;извлекаем список первого атрибута
      (setq at1_text (cdr (assoc 1 at1))) ;читаем значения атрибута
      
      (setq po (getpoint "\nУкажите местоположение стрелки выноски : "))
      (setq p1 (getpoint po "\nПоложение полки выноски: "))    
      	
      (command "_.mleader" po p1 at1_text)

      Можно полностью программно создавать стиль мультивыноски и сделать его текущим или использовать стиль текущий на данный момент.

  3. Антон 25.09.2014 20:21

    Отлично, то что надо, единственное не получается добавить второй атрибут в mleader под полку, аналогично тому как это выполнялось в блоке-выноске «vyn», спасибо за внимание

    • Михаил Орлов 16.10.2014 17:10
      (setq obj (car (entsel "\nВыберите блок: "))) ;просим выбрать блок
      (setq at1 (entget (entnext obj))) ;извлекаем список 1-го атрибута
      (setq at1_text (cdr (assoc 1 at1))) ;читаем значения атрибута
      (setq at2 (entget (entnext (entnext obj))));список 2-го атрибута
      (setq at2_text (cdr (assoc 1 at2));читаем значения 2-го атрибута
      
      (setq po (getpoint "\nУкажите местоположение стрелки выноски : "))
      (setq p1 (getpoint po "\nПоложение полки выноски: "))    
      
      (setq text (STRCAT at1_text "\n" at2_text)) ;соединяем текст	
      (command "_.mleader" po p1 text)
  4. Кирилл 16.01.2015 11:48

    У меня вставка блока работает не совсем корректно. Блок вставляется а атрибуты нет. Вылазит диалоговое окно, где меня просят ввести имена атрибутов Если посмотреть Окно команд (F2), то видно, что Autocad ругается на то, что «имя блока» — это не известная команда. То есть автокад принял имя блока за команду, а не вставил это имя в атрибут.
    Что я сделал не так?

    • Михаил Орлов 16.01.2015 12:22

      На запрос: Выберите блок: Вы должны указать на блок созданный программой mp_kub3.lsp. Именно из него программа считывает значения атрибутов. Если не получиться разобраться пришлите мне на почту: acadprog@gmail.com Вашу программу и файл автокада с кубом созданным программой mp_kub3.lsp. Я посмотрю и тогда отвечу.

    • Михаил Орлов 22.01.2015 06:57

      Блок можно вставить через vla-функции:
      Вместо строки:

      (command "_insert" "Vyn" po 1 1 0 bl_name V)

      Можно поставить следующие:

      Добираемся до указателя на пространство модели
      (setq acad_object (vlax-get-acad-object))                   
      (setq active_document (vla-get-activedocument acad_object)) 
      (setq model_space (vla-get-modelspace active_document)) 
      
      Вставляет блок с пустыми атрибутами
      (setq bl_Vs (vla-insertblock model_space (vlax-3d-point po) "Vyn" 1. 1. 1. 0))
      Определяем имена атрибутов 
      (setq atr1 (car(vlax-safearray->list(vlax-variant-value(vla-getattributes bl_Vs)))))     
      (setq atr2 (car(cdr(vlax-safearray->list(vlax-variant-value(vla-getattributes bl_Vs))))))
              
      Изменяем значение атрибутов.
      (vlax-put-property atr1 'TextString bl_name)
      (vlax-put-property atr2 'TextString V)

      Попробуйте, может так будет работать.

    • Виталий 05.02.2016 13:07

      У меня та же проблема! Пишу программу основываясь на ваших уроках. Делаю аналогичную функцию. Атрибуты не вставляются.

      • Виталий 05.02.2016 13:20

        Вот кусок кода

        (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

        Не знаю где ошибка =(

      • Михаил Орлов 05.02.2016 15:38

        Строка отключает вывод диалогового окна атрибутов при вставке блока:

        (setvar "ATTDIA" 0)

        Чтобы временно его отключить:

        (setq att (getvar "ATTDIA"))
        (setvar "ATTDIA" 0)

        В конце программы снова включаем:

        (setvar "ATTDIA" att)
        • Виталий 05.02.2016 18:30

          Спасибо! Сразу стало всё работать =)

          • Антон 11.03.2018 11:06

            Хотел бы дополнить. Если ATTREQ=0 то работать тоже не будет. Надо добавлять еще и это
            (setq attr (getvar "ATTREQ"))
            (setvar "ATTREQ" 1)

            В конце программы снова включаем:
            (setvar "ATTREQ" attr)

  5. Артем 06.05.2016 14:48

    Спасибо за код и подробное описание! Но никак не могу решить свою проблему. Необходимо извлечь из статического блока данные, записанные во вхождении в виде однострочного текста через пробел например «12 16 а8 гпр», количество переменных в тексте всегда разное. Прошу помощи так как попал в тупик

    • Михаил Орлов 09.05.2016 12:59

      В каком виде ваши данные хранятся в блоке (атрибут или доп. данные vla-объекта)? Вы не можете их извлечь или не можете разделить строку?

      • Артем 10.05.2016 06:29

        Блок уже создан и требуется из него извлечь данные хранящиеся в однострочном тексте. В доп данных vla объекта их нет и атрибутов к блоку нет.

  6. Valentina 05.01.2017 08:27

    Михаил, добрый день!
    Зачем добавлять в пользовательскую функцию «defun» локальные переменные, если она и без них работает?
    С уважением,
    Валентина

    • Михаил Орлов 08.01.2017 19:10

      В AutoLISP по умолчанию все создаваемые переменные глобальные, т.е. они будут храниться в памяти программы AutoCAD, после завершения команды Udim (пока Вы не закроете Автокад). Чтобы сделать их локальными (временными), их добавляют в описание функции DEFUN. И тогда после завершения команды Udim, они не болтаются в памяти AutoCAD.

  7. Дмитрий 26.10.2017 06:00

    Добрый день. Подскажите, как извлечь из dxf кода имя динамического блока

    • Михаил Орлов 02.11.2017 11:27
      (while(not(setq ent (car(entsel "\nУкажите блок или нажмите Esc : ")))))
      (setq list_ent (entget ent))
      (setq name_block (cdr(assoc 2 list_ent)))

      Но иногда? в каких-то версиях Автокада имена блоков в dxf-кодах слетают и Вы можете получить вместо имени что-то вроде «*U184»

      Надежней получить имя через vla-объект:

      (vl-load-com)
      (while(not(setq ent (car(entsel "\nУкажите блок или нажмите Esc : ")))))  
      (setq vla_obj (vlax-ename->vla-object ent))
      (setq name_block (vla-get-effectivename vla_obj))
  8. Сергей 12.08.2019 07:15

    Добрый день Михаил!
    В Уроке 13 «ВСТАВКА ДИНАМИЧЕСКОГО БЛОКА ИЗ LISP-ПРОГРАММЫ» при вставке динамического блока строка (command «_insert» «Vyn» po 1 1 0 bl_name V ) ; вставка блока выводилось окно ред атрибутов и после ОК программа воспринимала данные (bl_name и V) как неизвестные команды и прерывалась пока я не изменил системную переменную ATTDIA на 0

    • Сергей 12.08.2019 08:56

      Извините Михаил! Ответ нашел в Ваших комментариях….

      • Александр 20.09.2019 19:17

        Возможна реализация такой выноски
        1. Атрибут блока: если нет или nil пункт 2
        2. Видимость блока: если нет или nil пункт 3
        3. Имя блока: EffectiveName

  9. Евгений 23.04.2020 22:39

    Михаил, приветствую! огромная благодарность Вам за Ваши уроки! пытаюсь по ним освоить программирование lisp. Есть вопрос: у меня создан динамический блок с параметром видимости. на первом этапе изучения lisp я хочу создать код для вставки этого блока в чертеж с выбором видимости. То есть:
    1) запустил команду->
    2) указал точку вставки->
    3) выбрал видимость в диалоговом окне

    с пунктами 1 и 2 проблем не возникло, но каким образом должен выглядеть код программы чтобы реализовать пункт 3

    заранее благодарю!

Оставить комментарий

Ваш mail не будет опубликован.

Вы можете использовать HTML теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>