Урок 14. Изменение динамического блока из LISP-программы.

В последнее время в AutoCAD стали широко применяются динамические блоки.

Возможность управления динамическими блоками из LISP-программы открывает новые перспективы автоматизации проектов.

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

В начале, проведем не большие приготовления:

1) Создадим, блок с дополнительными данными, при помощи программы mp_kub3.

См. рис. 1

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

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

Эта программа рассмотрена в уроке: «LISP. Создание блока».

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

Откройте программу mp_kub3.lsp в редакторе Visual LISP.

Загрузите ее.

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

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

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

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

Программа создаст блок куба с размерами сторон 500. См. Рис. 2.

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

Рис. 2.  Блок с дополнительными данными.

2)    Вставим динамический блок «Vyn«, при помощи программы Udim.lsp. См. Рис. 3.

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

Рис. 3.  Программа Udim.

Динамический блок мы создавали в уроке: «Создание динамического блока». Если у Вас нет динамического блока «Vyn», скачайте его и разместите в путях поддержки Автокад.

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

Программу Udim.lsp мы создали в уроке: «Вставка динамическим блоком из LISP- программы».

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

Откройте программу Udim.lsp в редакторе Visual LISP.

Загрузите ее.

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

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

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

На следующий запрос «Выберите блок :» – нажмите <Esc>.

Программа нарисует выноску. См. Рис. 4

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

Рис. 4.  Динамический блок выноска.

Мы видим, что динамический блок размещен не совсем удачно. Хотелось удлинить как выносную линию, так и длину полки.

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

Выделите динамический блок и нажмите Ctrl+1. Откроется палитра свойств.  См. Рис. 5.

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

Рис. 5.  Динамические свойства.

На вкладке «Настройка» мы видим, что для изменения нам доступны:

Положение1 X – положение точки 1 относительно точки по координате X;

Положение1 Y – положение точки 1 относительно точки по координате Y;

Расстояние1 – длина выносной линии;

Угол1 – угол наклона выносной линии к оси X.

Расстояние2 – длина полки.

Давайте начнем с параметра Расстояние1 и попробуем изменить длину выносной линии.

Сохраните программу Udim.lsp под другим именем (Udim2.lsp).

Измените имя функции defun (Udim2).

После вставки динамического блока, используя функцию (entlast), возвращаем имя вставленного объекта.

Потом переводим обычный примитив в VLA-объект:

(vlax-ename->vla-object (entlast))

И сохраняем его в переменной din_bl:

(setq din_bl (vlax-ename->vla-object (entlast)))

Кроме этого, давайте добавим переменную sv1, в которой мы будем хранить имя изменяемого свойства:

(setq sv1 "Расстояние1")

См. Рис. 6.

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

Рис. 6.  Создаем переменные din_bl и sv1.

При помощи функции vla-getdynamicblockproperties считываем динамические свойства у VLA-объект din_bl:

 (vla-getdynamicblockproperties din_bl)

Давайте, чтобы следим за ходом наших действий, откроем Консоль Visual LISP.

Выделим строки, как на рис. 7, и загрузим выделенный фрагмент.

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

Рис. 7.   Считываем динамические свойства.

В окне Консоль Visual LISP мы видим, что наши динамические свойства вернулись в виде:

#<variant 8201 ...>

Чтобы, прочитать значение типа данных variant, используем функцию vlax-variant-value:

(vlax-variant-value (vla-getdynamicblockproperties din_bl))

Выделите эту строку и загрузите выделенный фрагмент. См. Рис. 8.

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

Рис. 8.   Считывает значение типа данных variant.

В окне Консоль Visual LISP мы видим, что наши динамические свойства вернулись в виде безопасного массива:

#<safearray...>

При помощи функции vlax-safearray->list преобразуем массив в список:

(vlax-safearray->list(vlax-variant-value (vla-getdynamicblockproperties din_bl)))

Выделите эту строку и загрузите выделенный фрагмент. См. Рис. 9.

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

Рис. 9.  Преобразуем массив в список.

Эта строка вернет нам список с нашими динамическими свойствами (Положение1 X, Положение1 Y, Расстояние1 и так далее), которые представлены в виде VLA-объектов:

(#<VLA-OBJECT IAcadDynamicBlockReferenceProperty 18cb5724>
 #<VLA-OBJECT IAcadDynamicBlockReferenceProperty 18cb5664>
 #<VLA-OBJECT IAcadDynamicBlockReferenceProperty 18cb68a4>
 #<VLA-OBJECT IAcadDynamicBlockReferenceProperty 18cb6a84>
 #<VLA-OBJECT IAcadDynamicBlockReferenceProperty 18cb6744>
 #<VLA-OBJECT IAcadDynamicBlockReferenceProperty 18cb6a44>
 #<VLA-OBJECT IAcadDynamicBlockReferenceProperty 18cb6864>)

Чтобы, в списке оставить только то динамическое свойство, которое нам нужно, применим функцию vl-remove-if-not, которая в общем виде выглядит так:

(vl-remove-if-not<тест-функция> <список>)

Функция vl-remove-if-not удаляет из списка все элементы, возвращающие nil при проверке тест-функцией.

<тест-функция> - функция, применяемая для проверки поочередно к каждому элементу списка.
<список> - список из которого нужно удалить объекты.

В качестве тест-функции мы будем использовать следующее выражение:

(lambda (x) (= (vla-get-propertyname x) sv1))

Функция lambda создает безымянные пользовательские функции, которые можно определить и тут же выполнить. В общем виде она выглядит так:

(lambda <аргументы> <выражения>)

Функция vla-get-propertyname считывает имя свойства.

Выражение (= (vla-get-propertyname x) sv1) – сравнивает имя свойства, полученное из элемента списка, с именем, которое хранится в переменной sv1 («Расстояние1»). Если они = , то возвращает Т, в противном случаи nil.

Добавляем в программу следующие строки:

(vl-remove-if-not(lambda (x) (= (vla-get-propertyname x) sv1))
  < наш список>
) ; end vl-remove-if-not

Выделим строки, как на рис. 10, и загрузите выделенный фрагмент.

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

Рис. 10.  Оставляем только нужное свойство.

Функция vl-remove-if-not оставит в списки, только одно динамическое свойство.

Чтобы получить само свойство, а не список с одним свойством, применяем функцию car, которая извлекает первый элемент из списка.

(car (vl-remove-if-not '(lambda (x) (= (vla-get-propertyname x) sv1))
       (vlax-safearray->list(vlax-variant-value
       (vla-getdynamicblockproperties din_bl)))
     ); end vl-remove-if-not
); end car

И сохраняем его в переменной din_sv:

(setq din_sv (car (vl-remove-if-not '(lambda (x) (= (vla-get-propertyname x) sv1))
      (vlax-safearray->list(vlax-variant-value
      (vla-getdynamicblockproperties din_bl)))
    ); end vl-remove-if-not
  ); end car
); end setq

Добавляем выше сказанное в программу.

Выделите строки, как на рис. 11, и загрузите выделенный фрагмент.

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

Рис. 11.  Динамическое свойство.

Мы видим, что выделенный фрагмент возвращает нам, только одно динамическое свойство в виде VLA-объекта.

Давайте проверим то ли свойство мы получили. Для этого добавим следующую строку:

(vla-get-propertyname din_sv) – которая считывает имя свойства.

См. Рис. 12.

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

Рис. 12.  Имя динамического свойства.

Мы видим, что в переменной din_sv хранится динамическое свойство (VLA-объект), которое нам нужно. Последнюю строчку из программы можно удалить (мы использовали ее, только для проверки).

Нам остается, только изменить значение динамического свойства. Давайте поменяем значение свойства «Расстояние1» на 350.

В начале нужно привести это значение к типу variant. Для этого используем функцию vlax-make-variant, которая в общем виде выглядит так:

(vlax-make-variant <значение> <тип>)
<значение> - значение присваиваемое варианту.
<тип> - тип данных значения (вещественное число, строка и так далее)

Нужно, чтобы новое значение было того же типа, что и старое.

Чтобы определить тип старого значения, добавляем следующее выражение:

(vlax-variant-type (vla-get-value din_sv))
vla-get-value – считает значение din_sv
vlax-variant-type – возвращает его тип.

Добавьте, эту строку в программу.

Выделите ее и загрузите выделенный фрагмент. См. Рис. 13.

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

Рис. 13.   Тип данных старого значения.

Строка вернет нам код типа «5», что соответствует типу: Вещественное число с двойной точностью.

Преобразуем наше новое значение в тип variant:

(vlax-make-variant 350 (vlax-variant-type (vla-get-value din_sv)))

При помощи функции vla-put-value меняем старое значение на новое.

В общем виде функция vla-put-value выглядит так:

(vla-put-value  <vla-свойство> <новое значение>)
<vla-свойство> - свойство значение которого нужно изменить;
<новое значение> - новое значение. Должно иметь тип variant

Добавляем выражение, которое меняет значение:

(vla-put-value  din_sv  (vlax-make-variant 350 (vlax-variant-type (vla-get-value din_sv))))

Чтобы значение вступило в силу vla-объект динамического блока нужно обновить. Делаем это при помощи функции vla-update

(vla-update din_bl)

Добавляем все выше сказанное. Выделите строки, как на рис. 14, и загрузите выделенный фрагмент.

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

Рис. 14.   Изменение динамического свойства.

Перейдите в Автокад. Выносная линия у динамического блока стала длинней. См. Рис. 15.

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

Рис. 15.   Динамического блок изменился.

Чтобы остальные динамические свойства нам изменять стало проще, преобразуем часть кода в пользовательскую функцию Change_din_sv:

(defun Change_din_sv (din_bl sv new_value / din_sv)
    (setq din_sv (car(vl-remove-if-not '(lambda (x) (= (vla-get-propertyname x) sv))
                               (vlax-safearray->list(vlax-variant-value (vla-getdynamicblockproperties din_bl)))
                               ); end vl-remove-if-not
                         ); end car
     ); end setq
     (vla-put-value din_sv (vlax-make-variant new_value (vlax-variant-type (vla-get-value din_sv))))
     (vla-update din_bl)
  ) ; end defun

Для вызова функции в общем виде используется выражение:

(Change_din_sv din_bl sv new_value) , где:
din_bl – динамический блок, в котором нужно поменять значение динамического свойства;
sv – имя динамического свойства;
new_value – новое значение динамического свойства.

Добавляем в программу пользовательскую функцию Change_din_sv, и вызываем ее используя в качестве имени динамического свойства «sv1», а в качестве нового значения «350». См. Рис. 16.

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

Рис. 16.   Пользовательская функция изменения динамического свойства.

Теперь, для того, чтобы поменять угол наклона выносной линии достаточно добавить две строчки:

(setq sv2 "Угол1") – создаем переменную sv2 с именем изменяемого свойства
(Change_din_sv din_bl sv2 (/ pi 2)) – меняем значения свойства на (/ pi 2).

(/ pi 2) – угол 90 градусов в радианах.

Добавляем эти строки. См. Рис. 17.

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

Рис. 17.  Изменение свойства «Угол1».

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

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

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

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

На следующий запрос «Выберите блок :» – нажмите <Esc>.

Программа нарисует выноску. См. Рис. 18.

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

Рис. 18.  Угол выносной линии изменился.

Мы видим, что значения динамических свойств (Расстояние1 и Угол1) изменились.

Но в каждом конкретном случаи, мы заранее не знаем какие значения динамических свойств лучше задать. Поэтому попросим сделать это пользователя. Пусть, после указания блока базовая точка, прикрепляется к блоку сама, а точку «1» пользователь указывает сам.

Попросим пользователя указать точку «1», при помощи функции getpoint:

(setq p1 (getpoint po "\nУкажите выносную линию: "))

Значения сохраним в переменной p1.

Расстояние между точками ро и р1 определим при помощи функции distance:

(setq ras (distance po p1))

Значения сохраним в переменной ras.

Угол наклона определим при помощи функции angle:

(setq ugl (angle po p1))

Значения сохраним в переменной ugl.

В функцию Change_din_sv меняющую свойства «Расстояние1» вместо 350 вставим ras.

В функцию Change_din_sv меняющую свойства «Угол1» вместо (/ pi 2) вставим ugl.

Добавим две сточки меняющие длину полки на значение 290.

(setq sv3 "Расстояние2")
(Change_din_sv din_bl sv3 290)

В результате наша программа примет следующий вид. См. Рис. 19.

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

Рис. 19.  Запрос у пользователя значений динамический свойств.

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

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

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

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

На запрос «Укажите выносную линию:» — Укажите вторую точку линии.

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

На запрос «Укажите выносную линию:» — Укажите вторую точку линии в другом месте.

На следующий запрос «Выберите блок :» – нажмите <Esc>.

Программа нарисует две выноски к одному блоку. См. Рис. 20.

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

Рис. 20.  Значения динамический свойств указывает пользователь.

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

Окончательный вариант программы. См. Рис. 21.

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

Рис. 21.  Программа Udim2.lsp.

Код программы:

(defun c:Udim2 (/ obj vla_obj V po bl_name osm p1 ras ugl din_bl sv1 sv2 sv3) 
     (vl-load-com) ; загружаем функции расширения 
     ;---------------------------------------------------------------------------------------------------------- 
     ;--------------- Функция изменения динамического свойства --------------------- 
     ;---------------------------------------------------------------------------------------------------------- 
     (defun Change_din_sv (din_bl sv new_value / din_sv)
          (setq din_sv (car (vl-remove-if-not '(lambda (x) (= (vla-get-propertyname x) sv)) 
                                       (vlax-safearray->list(vlax-variant-value (vla-getdynamicblockproperties din_bl))) 
                                   ); end vl-remove-if-not
                            ); end car 
           ); end setq 
          (vla-put-value din_sv (vlax-make-variant new_value (vlax-variant-type (vla-get-value din_sv)))) 
          (vla-update din_bl) 
     ); end defun 
     ;--------------------------------------------------------------------------------------------------------------- 
     (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 p1 (getpoint po "\nУкажите выносную линию: ")) ; запрос точки 1 
                    (setq ras (distance po p1))                         ; определение расстояния 
                    (setq ugl (angle po p1))                              ; угол наклона прямой 
                    (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) ; вставка блока 
                    (setq din_bl (vlax-ename->vla-object (entlast))) 
                    (setq sv1 "Расстояние1") 
                    (Change_din_sv din_bl sv1 ras) 
                    (setq sv2 "Угол1") 
                    (Change_din_sv din_bl sv2 ugl) 
                    (setq sv3 "Расстояние2") 
                    (Change_din_sv din_bl sv3 290) 

                    (setvar "osmode" osm) ; возвращает привязки пользователя 
               );end progn 
          ); end if
     ); end while 
); end_defun

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

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

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

Также пишите в комментариях:

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

Если, что-то не получилось. Пишите, постараюсь помочь.

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

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

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

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

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

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

Google

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

15 комментарии на “Урок 14. Изменение динамического блока из LISP-программы.

  1. power85 10.09.2014 11:42

    Спасибо, очень интересно.

  2. Кирилл 27.11.2014 02:30

    Замечательные уроки!
    В этом примере мне не хватает, чтобы длина полочки менялась в зависимости от длины текста.

    В будущем очень хочется увидеть пример программы по автоматической нумерации блоков, с возможностью перенумерации

    • Михаил Орлов 11.12.2014 10:33

      О какой нумерации идет речь? Для какой цели нужна эта нумерация? AutoCAD при вставке нумерует все примитивы в своей базе данных.

      • Тимофей 01.12.2015 12:45

        Спасибо, за Ваши уроки! Очень помогает, буквально несколько дней занимаюсь lisp, а уже серьезно автоматизировал работу.
        По поводу нумерации, мне например, очень помогла бы автоматическая простановка маркировки. У меня есть около 15 блоков -заготовок с различными параметрами: длина, ширина и различные формы вырезов (решетки с вырезами). Я расставляю эти заготовки по чертежу (до 1000 штук) и нумерую вручную. Собственно задача такова, что при вставке нового блока, он должен анализировать параметры всех уже вставленных блоков и, в случае если есть совпадение абсолютно по всем атрибутам — присвоить такой же номер, если нет — присвоить новый.

  3. Влад 09.05.2015 09:53

    Хорошие уроки.
    Как изменить параметр видимости?

    • Михаил Орлов 09.05.2015 21:29

      Параметр видимости чего?
      Если атрибута, то

      (setq obj (car (entsel "\nВыберите блок: "))) ;блок с атрибутами
      (setq at1 (entnext obj))
      (setq vla_at1 (vlax-ename->vla-object at1))

      Скрыть первый атрибут:

      (vla-put-visible vla_at1 0)
      (vla-update vla_at1)

      Показать первый атрибут:

      (vla-put-visible vla_at1 1)
      (vla-update vla_at1)
  4. Алена 10.05.2017 17:04

    Добрый день! Не подскажите, какой тип данных скармливать вашей функции Change_din_sv (изменение динамического блока) в качестве аргумента для изменения параметра «отражения» (отражение/без отражения)? На всё ругается — тип не торт:)

    • Михаил Орлов 15.05.2017 09:54

      Динамический блок должен иметь это динамическое свойство (в примере этого свойства нет). По умолчанию значение этого свойства = 0, что соответствует состоянию без отображения. Значение = 1 — соответствует состоянию отображения

  5. Виталий 05.09.2017 12:44

    Добрый день.
    В своей программе пытаюсь в функцию Change_din_sv передать существующий блок для изменения динамических параметров, но acad упорно выдает ошибку Select object: ; error: bad argument type: numberp: nil

    (setq obj (car (entsel «\nВыберите блок: «)))
    (setq din_bl (vlax-ename->vla-object obj))
    (setq sv1 «X/2»)
    (Change_din_sv din_bl sv1 (/ Zb 2))
    (setq sv2 «Zd/2»)
    (Change_din_sv din_bl sv2 (/ Zd 2))
    (setq sv3 «L0L1»)
    (Change_din_sv din_bl sv3 L0L1)
    (setq sv4 «L0L»)
    (Change_din_sv din_bl sv4 L)

    Подскажите, что надо подправить?

    • Михаил Орлов 21.09.2017 15:32

      Пришлите мне на почту acadprog@gmail.com вашу программу и динамический блок, в котором Вы пытаетесь изменить динамическое свойство.

  6. Александра 19.05.2018 13:42

    Здравствуйте. Подскажите, пожалуйста, а как получить само значение динамического свойства?
    Если просто использовать (vla-get-value din_sv), то в результате получаем #
    А как теперь из этой строки извлечь само это число -1801,76544561827 ?

    • Михаил Орлов 06.06.2018 20:25

      (vla-get-propertyname din_sv)

  7. Дмитрий 05.06.2018 13:11

    Здравствуйте!))) Очень хорошо помогает ваш сайт!!)) Спасибо за открытость и силу воли которая Вам позволяет не лениться, и вдаваясь в мелочи, создавать легкодоступные обучающие материалы!!!)))

    К сожалению у меня не получилось получить доступ к атрибутам ( и соответственно изменить) Эти атрибуты в дин.блоке в виде полей организованы..

    • Михаил Орлов 06.06.2018 20:23

      В данном уроке показано как изменять динамические свойства блока.
      Изменение атрибутов происходить по тому же алгоритму, только вместо функции vla-getdynamicblockproperties надо использовать vla-getattributes

      После того как Vla-имя атрибута найдено:
      Прочитать текст атрибута можно так:

      (vla-get-TextString vla_atr)

      Изменить текст атрибута :

      (vla-put-TextString vla_atr new_value)

      vla_atr — переменная в которой храниться Vla-имя атрибута
      new_value — новое значение атрибута

      Удачи!!!

      • Дмитрий 07.06.2018 17:27

        Спасибо огромное!))) Вы не только тут мне ответили, но и в личном сообщении на почте!!!))) Спасибо Вам за щедрость!!)))

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

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

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