Schöck
| Правила | Регистрация | Пользователи | Поиск | Сообщения за день | Все разделы прочитаны |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > Лисп для записи свойств одно динамического блока в атрибуты другого блока

Лисп для записи свойств одно динамического блока в атрибуты другого блока

Ответ
Поиск в этой теме
Непрочитано 30.09.2020, 13:27 #1
Лисп для записи свойств одно динамического блока в атрибуты другого блока
Сыч
 
Регистрация: 05.04.2011
Сообщений: 13

Здравствуйте.
Есть динамический блок (ДБ) "Опора" и другой ДБ "Данные опоры".
ДБ "Опора" содержит атрибут "НОМЕР" и параметр растягивания "Габарит".
ДБ "Данные опоры" содержит атрибуты "Н" и "Г".
Хотел написать Лисп со следующим функционалом: выбираешь ДБ "Опора" (один из вставленных на чертеже), далее выбираешь ДБ "Данные опоры" (тоже один из вставленных на чертеже), в результате значение атрибута "НОМЕР" записывается в атрибут "Н", значение (длина) параметра растягивания "Габарит" записывается в атрибут "Г". В идеале записанные значения атрибутов "Н" и "Г" должны представлять из себя не текст, а поля (но это уже задача максимум).
В знании AutoLISP я очень слаб. На старте столкнулся с тем, что известными мне функциями (например, entget) извлечь атрибуты блока не получается, значения динамических параметров тоже не извлекаются. Порылся на форуме, ничего подходящего не нашел (может плохо искал). В старой книге Кудрявцева по AutoLISP от 1999 года такого тоже нет, тогда вообще не было динамических блоков.
Просьба подсказать, реализуема ли вообще моя задумка с помощью Лиспа? Какие команды могут извлекать полный набор свойств ДБ и передавать значение другому ДБ? В общем, кто в теме, просьба оказать помощь.
Просмотров: 1526
 
Непрочитано 30.09.2020, 13:43
#2
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 37,817


Поиск по форуму: установка динамических свойств, программное создание поля и т.п. Кирпичики есть.
__________________

---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 30.09.2020, 15:02
1 | #3
skkkk


 
Регистрация: 20.03.2008
Сообщений: 2,544


Задумка на лиспе вполне и довольно несложно реализуема. У LeeMac'a есть функции по чтению/редактированию атрибутов и свойств динамических блоков.
Dynamic Block Functions
Attribute Functions

Для новичка в лиспе задачка будет, конечно, трудновата. Если нужен именно код (а не поучиться), я готов нацарапать на досуге, думаю, делов там минут на 15. Только попрошу скинуть файл с этими блоками.
skkkk на форуме  
 
Автор темы   Непрочитано 30.09.2020, 16:21
#4
Сыч


 
Регистрация: 05.04.2011
Сообщений: 13


skkkk, спасибо за наводку. Попробую сам для начала поковыряться.

----- добавлено через ~21 ч. -----
В результате получилось вот что
Код:
[Выделить все]
 (defun c:peredacha_N_G ()
  (vl-load-com)
  (setq opora (car (entsel "Выберите блок КС_Опора: ")))
  (setq vla_opora (vlax-ename->vla-object opora))

;; Get Dynamic Block Property Value - Lee Mac

  (setq gabarit (strcase "Габарит"))
  (setq g (vl-some '(lambda ( x ) (if (= gabarit (strcase (vla-get-propertyname x))) (vlax-get x 'value))) (vlax-invoke vla_opora 'getdynamicblockproperties)))
  
;(print g)
;(princ)

;; Get Attribute Value - Lee Mac

  (setq nomer (strcase "НОМЕР"))
  (setq n (vl-some '(lambda ( att ) (if (= nomer (strcase (vla-get-tagstring att))) (vla-get-textstring att))) (vlax-invoke vla_opora 'getattributes)))

;(princ n)
;(princ)

 (setq dannie (car (entsel "Выберите блок КС_Данные опоры: ")))
 (setq vla_dannie (vlax-ename->vla-object dannie)) 

;; Set Attribute Value - Lee Mac

 (setq g_d (strcase "Г"))
 (vl-some '(lambda ( att ) (if (= g_d (strcase (vla-get-tagstring att))) (progn (vla-put-textstring att g) g))) (vlax-invoke vla_dannie 'getattributes))
  
 (setq n_d (strcase "Н"))
 (vl-some '(lambda ( att ) (if (= n_d (strcase (vla-get-tagstring att))) (progn (vla-put-textstring att n) n))) (vlax-invoke vla_dannie 'getattributes))
  
)
Сыч вне форума  
 
Автор темы   Непрочитано 01.10.2020, 13:20
#5
Сыч


 
Регистрация: 05.04.2011
Сообщений: 13


Со вставкой номера и габарита полем не разобрался.
Смотрел вот эту тему https://forum.dwg.ru/showthread.php?t=120398.
Просьба оказать помощь.
Файл с блоками прилагаю.Опора.dwg

----- добавлено через ~19 ч. -----
Попробовал запустить лисп из темы https://autolisp.ru/2010/05/30/field-proceed-2/
Выдает ошибку: "Укажите точку для простановки поля <Отмена> : ; ошибка: неверный тип аргумента: stringp nil".

В комментарии к теме https://autolisp.ru/2011/07/07/x32x64objectid/ говорится, что на новых версиях AutoCAD не сработают предложенные методы.

Смотрел еще тему https://forum.dwg.ru/showthread.php?t=14528 про вставку поля в таблицу, но там тоже лиспы 2007 года.

Где ж рабочий алгоритм взять?
Сыч вне форума  
 
Непрочитано 02.10.2020, 14:35
#6
skkkk


 
Регистрация: 20.03.2008
Сообщений: 2,544


Цитата:
Сообщение от Сыч Посмотреть сообщение
В результате получилось вот что
Что-то не сработал у меня этот код на приложенном файле.


Дерзну для начала дать несколько рекомендаций.

1. Не забываем локализовывать переменные. Для этого нужно перечислить имена переменных (определяемых с помощью setq в коде) после слэша внутри первых скобок, следующих за defun. Если этого не сделать, то они станут глобальными (будут находиться в памяти автокада вплоть до его закрытия, хотя логично их существование ограничить только временем выполнения функции). Если переменные локализованы, то при завершении функции они стираются из памяти. Не то, чтобы в данном случае это было критично, но для порядку стоит это делать по разным причинам, сейчас углубляться не будем. Бывают случаи, когда нужно переменную сделать глобальной сознательно (то есть не вписывать ее после слэша), например, для запоминания последних введенных значений функций, начинающихся на get... (getstring, getint, getreal и т.д.). Но это - следующий этап познания основ. Пока пропустим.

2. От многих опытных программистов многократно слышал рекомендации делить код на условные блоки (разделы). И я считаю это очень правильным. Наводит порядок в коде и в голове. Делить нужно именно пространственно, то есть, в начале кода - первое, затем - второе, и в конце - третье. Это не всегда может быть в точности реализуемо с учетом логики программы, но стремиться к этому надо. В общем случае это примерно такой перечень:
  • а) блок ввода пользовательских данных (взаимодействие с пользователем);
  • б) блок анализа и вычислений (под вычислениями тут стоит понимать не только математические расчеты, но и любые действия по поиску и составлению нужных результатов, например, составление нужных текстовых строк);
  • в) блок вывода результатов и построений (а также прочих изменений чертежа или объектов).
Применительно к нашему случаю это будет выглядеть примерно так:
  • а) запросы на выбор двух блоков;
  • б) чтение данных из одного блока, преобразование числовых значений в строки (потому что содержимое атрибута есть строка, то есть, даже, если это число, то в формате текста), составление строк с полями (в данном контексте можем условно назвать их вычислениями), запоминание этих вычислений в переменные;
  • в) запись вычисленных значений строк в атрибуты второго блока.

3. Указывая ссылки, я имел в виду, что следует использовать готовые функции, подставляя в них полученные от пользователя (или вычисленные в коде значения) в качестве аргументов. Например, функция Lee Mac'a LM:vl-setattributevalue имеет следующие аргументы:
Код:
[Выделить все]
 ( blk tag val )
где blk - vla-указатель на вхождение (экземпляр) блока, tag - имя атрибута, val - его значение.
Из этих готовых к применению функций впоследствии (и в идеале) стоит собрать свою собственную библиотеку, а не выдергивать из них куски и повторять их по несколько раз в одном коде. Тут встает важный вопрос об организации своей библиотеки функций. Если эта нужная (своя или чужая) функция используется только в этом конкретном коде, то ее надо поместить в этом же файле в конце, а если она используется в нескольких своих кодах, то ее стоит добавить в библиотеку (отдельный lsp-файл или несколько файлов, которым нужно обеспечить автозагрузку). В данном случае мы приведем коды нужных вспомогательных функций внутри нашего кода.

Вот первый вариант кода с пояснениями в комментариях. Он просто считывает нужные атрибут и дин.параметр первого блока и добавляет их в соответствующие атрибуты второго блока:
Код:
[Выделить все]
 
(defun c:peredacha_N_G ( / opora dannie vla_opora vla_dannie nomer gabarit)
	(vl-load-com)
	;;; Блок ввода пользовательских данных
	(setq opora (car (entsel "Выберите блок КС_Опора: ")))
	(setq dannie (car (entsel "Выберите блок КС_Данные опоры: ")))
	
	
	
	;;; Блок анализа и вычислений  
	(if (and opora dannie) ;;; ЕСЛИ И один И второй объекты выбраны, 
		;;; выполняем серию действий
		(progn  ;;; программная "скобка" для if (чтобы можно было использовать несколько действий, если условие выполнено)
			;;; преобразовываем entity-name'ы объектов во vla-указатели 
			(setq vla_opora (vlax-ename->vla-object opora)) 
			(setq vla_dannie (vlax-ename->vla-object dannie)) 
			;;; читаем и сохраняем в переменную "nomer" значение из атрибута "НОМЕР" блока "КС_Опора" (используя библиотечную функцию)
			(setq nomer (LM:vl-getattributevalue vla_opora "НОМЕР"))
			;;; читаем и сохраняем в переменную "gabarit" значение из дин.параметра "ГАБАРИТ" блока "КС_Опора" (используя библиотечную функцию)
			(setq gabarit (LM:getdynpropvalue vla_opora "Габарит"))
			;;; преобразуем значение габарита (число) в строку
			(setq gabarit (rtos gabarit 2 1))
		) ; end of progn
		;;; ЕСЛИ же хотя бы один из объектов не выбран, то пишем в командную строку об этом
		(princ "\nВыбор объектов не осуществлен")
	) ; end of if	
			
	;;; Блок вывода результатов и построений
	(if (and nomer gabarit) ;;; ЕСЛИ получены оба значения, 
		;;; назначаем атрибутам блока "КС_Данные опоры" нужные значения (используя библиотечную функцию)
		(progn
			(LM:vl-setattributevalue vla_dannie "Н" nomer)
			(LM:vl-setattributevalue vla_dannie "Г" gabarit)
		) ; end of progn
	) ; end of if
) ; end of defun



;;;---------------------------------------------------------------------------------------------------------------------
;;; Библиотечные функции
;;;---------------------------------------------------------------------------------------------------------------------



;; Get Attribute Value  -  Lee Mac
;; Returns the value held by the specified tag within the supplied block, if present.
;; blk - [vla] VLA Block Reference Object
;; tag - [str] Attribute TagString
;; Returns: [str] Attribute value, else nil if tag is not found.

(defun LM:vl-getattributevalue ( blk tag )
    (setq tag (strcase tag))
    (vl-some '(lambda ( att ) (if (= tag (strcase (vla-get-tagstring att))) (vla-get-textstring att))) (vlax-invoke blk 'getattributes))
)



;; Set Attribute Value  -  Lee Mac
;; Sets the value of the first attribute with the given tag found within the block, if present.
;; blk - [vla] VLA Block Reference Object
;; tag - [str] Attribute TagString
;; val - [str] Attribute Value
;; Returns: [str] Attribute value if successful, else nil.

(defun LM:vl-setattributevalue ( blk tag val )
    (setq tag (strcase tag))
    (vl-some
       '(lambda ( att )
            (if (= tag (strcase (vla-get-tagstring att)))
                (progn (vla-put-textstring att val) val)
            )
        )
        (vlax-invoke blk 'getattributes)
    )
)


;; Get Dynamic Block Property Value  -  Lee Mac
;; Returns the value of a Dynamic Block property (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)

(defun LM:getdynpropvalue ( blk prp )
    (setq prp (strcase prp))
    (vl-some '(lambda ( x ) (if (= prp (strcase (vla-get-propertyname x))) (vlax-get x 'value)))
        (vlax-invoke blk 'getdynamicblockproperties)
    )
)
Однако, если нам надо вставить в атрибуты второго блока поля, то не нужно читать программно атрибут и дин. параметр первого блока. Тут нам придется сначала определить ID нужных объектов и собрать их коды поля. Для этого надо, находясь в режиме редактирования атрибута, дважды кликнуть на заранее созданном вручную поле - и в окне редактирования поля посмотреть его формулу. Это ничто иное, как текстовая строка, которую надо "собрать" и вставить в атрибут. Вот вариант с полями:
Код:
[Выделить все]
 
(defun c:peredacha_N_G ( / opora dannie vla_opora vla_dannie attr_vla_obj attr_ID fieldcode_1 fieldcode_2)
	(vl-load-com)
	;;; Блок ввода пользовательских данных
	(setq opora (car (entsel "Выберите блок КС_Опора: ")))
	(setq dannie (car (entsel "Выберите блок КС_Данные опоры: ")))
	;;; Блок анализа и вычислений  
	(if (and opora dannie) ;;; ЕСЛИ И один И второй объекты выбраны, 
		;;; выполняем серию действий
		(progn  ;;; программная "скобка" для if (чтобы можно было использовать несколько действий, если условие выполнено)
			;;; преобразовываем entity-name'ы объектов во vla-указатели 
			(setq vla_opora (vlax-ename->vla-object opora)) 
			(setq vla_dannie (vlax-ename->vla-object dannie))
			;;; извлекаем vla-объект атрибута функцией get_attr_by_tag 
			(setq attr_vla_obj (get_attr_by_tag vla_opora "НОМЕР"))
			;;; извлекаем ID этого атрибута (тоже вспомогательной функцией)
			(setq attr_ID (Get-ObjectID-x86-x64  attr_vla_obj))
			;;; собираем код первого поля
			(setq fieldcode_1 
				(strcat
					"%<\\AcObjProp Object(%<\\_ObjId "
					attr_ID
					">%).TextString>%"
				)
			)
			;;; собираем код второго поля
			(setq fieldcode_2
				(strcat
					"%<\\AcObjProp Object(%<\\_ObjId "
					(Get-ObjectID-x86-x64  vla_opora)
					">%).Parameter(15).UpdatedDistance \\f \"%lu2%pr1%ds44\">%"
				)
			)
		) ; end of progn
		;;; ЕСЛИ же хотя бы один из объектов не выбран, то пишем в командную строку об этом
		(princ "\nВыбор объектов не осуществлен")
	) ; end of if	
			
	;;; Блок вывода результатов и построений
	(if (and fieldcode_1 fieldcode_1) ;;; ЕСЛИ получены оба значения, 
		(progn
			;;; назначаем атрибутам блока "КС_Данные опоры" нужные значения (используя библиотечную функцию)
			(LM:vl-setattributevalue vla_dannie "Н" fieldcode_1)
			(LM:vl-setattributevalue vla_dannie "Г" fieldcode_2)
			(vl-cmdf "_regenall")
		) ; end of progn
	) ; end of if
) ; end of defun



;;;---------------------------------------------------------------------------------------------------------------------
;;; Библиотечные функции
;;;---------------------------------------------------------------------------------------------------------------------


;; Set Attribute Value  -  Lee Mac
;; Sets the value of the first attribute with the given tag found within the block, if present.
;; blk - [vla] VLA Block Reference Object
;; tag - [str] Attribute TagString
;; val - [str] Attribute Value
;; Returns: [str] Attribute value if successful, else nil.

(defun LM:vl-setattributevalue ( blk tag val )
    (setq tag (strcase tag))
    (vl-some
       '(lambda ( att )
            (if (= tag (strcase (vla-get-tagstring att)))
                (progn (vla-put-textstring att val) val)
            )
        )
        (vlax-invoke blk 'getattributes)
    )
)


(defun get_attr_by_tag (block_ref attr_tag / attr_vla_obj)
	(vl-some '(lambda (x)
					(= attr_tag (vla-get-tagstring (setq attr_vla_obj x)))
			  )
			  (vlax-safearray->list (vlax-variant-value (vla-getattributes block_ref)))
	)
	attr_vla_obj
)


(defun Get-ObjectID-x86-x64 (obj / util)
  (setq util (vla-get-Utility (vla-get-activedocument (vlax-get-acad-object))))
  (if (= (type obj) 'ENAME)(setq obj (vlax-ename->vla-object obj)))
  (if (= (type obj) 'VLA-OBJECT)
     (if (> (vl-string-search "x64" (getvar "platform")) 0)
       (vlax-invoke-method util "GetObjectIdString" obj :vlax-False)
       (rtos (vla-get-objectid obj) 2 0)
     )
  )
)

Последний раз редактировалось skkkk, 02.10.2020 в 15:20.
skkkk на форуме  
 
Автор темы   Непрочитано 03.10.2020, 08:47
#7
Сыч


 
Регистрация: 05.04.2011
Сообщений: 13


skkkk, спасибо огромное за столь развернутый и толковый ответ.

Советы безусловно дельные. Прокомментирую, пожалуй, только второй. Блочное выполнение лиспа - признак мастерства. Ну а так как у меня с этим не очень, то блочная структура для восприятия мне тяжеловата. Когда операции прописаны одна за другой шаг за шагом, воспринимается, пишется и отслеживается надежнее. Отсюда, кстати, вышли и раздельный запрос на блоки, и ввод дополнительных промежуточных переменных.

У меня появилась еще пара вопросов.
Бывают ситуации, когда исходный блок КС_Опора размещается в пространстве модели, а принимающий блок КС_Данные опоры размещается на листе. При ручном задании полей в атрибутах номера и габарита нет проблем дать ссылку на блок в модели - достаточно при выборе объекта для поля щелкнуть по блоку в видовом экране, блок без проблем воспринимается и распознается. То есть получается организовать связь блока в модели с атрибутом блока на листе. Возможно ли такую функцию реализовать в данном лиспе? Например, использовать не функцию entsel?

В ходе работы над данным лиспом я столкнулся с проблемой поиска информации по функциям LISP. Существует ли какая-то книга, сайт, справочник и т.п., где приведен максимально полный перечень функций LISP с синтаксисом и описанием аргументов?

Странно почему мой лисп не сработал у вас - я выкладывал рабочий обкатанный вариант. Может быть дело в "битости" файла Опора.dwg - после скачивания на другом компьютере он запросил восстановление.
Сыч вне форума  
 
Непрочитано 03.10.2020, 08:59
#8
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 8,842


Цитата:
Сообщение от Сыч Посмотреть сообщение
Существует ли какая-то книга, сайт, справочник и т.п., где приведен максимально полный перечень функций LISP с синтаксисом и описанием аргументов?
хэлп от разработчика программы)
Сергей812 вне форума  
 
Непрочитано 03.10.2020, 09:35
#9
skkkk


 
Регистрация: 20.03.2008
Сообщений: 2,544


Цитата:
Сообщение от Сыч Посмотреть сообщение
То есть получается организовать связь блока в модели с атрибутом блока на листе. Возможно ли такую функцию реализовать в данном лиспе? Например, использовать не функцию entsel?
Можно и используя функцию entsel. Например, обработав "пустой" ввод (Enter без выбора объекта):
Код:
[Выделить все]
 (setq en (entsel "\nВыберите объект <Смена пространства>"))
(if (null en) 
	(progn
		(vl-cmdf "_.MSPACE")
		(setq en (entsel "\nВыберите объект"))
		(if en (setq en (car en)))
	)
)
Или добавить ключевые слова (опции команды):
Код:
[Выделить все]
 (initget "Смена Что")
(setq en (entsel "\nВыберите объект [Смена пространства/Что угодно]"))
(if (= en "Смена") 
	(progn
		(vl-cmdf "_.MSPACE")
		(setq en (entsel "\nВыберите объект"))
		(if en (setq en (car en)))
	)
)

Цитата:
Сообщение от Сыч Посмотреть сообщение
Существует ли какая-то книга, сайт, справочник и т.п., где приведен максимально полный перечень функций LISP с синтаксисом и описанием аргументов?
Мне нравится эта.
skkkk на форуме  
 
Автор темы   Непрочитано 03.10.2020, 14:26
#10
Сыч


 
Регистрация: 05.04.2011
Сообщений: 13


Цитата:
Сообщение от skkkk Посмотреть сообщение
Можно и используя функцию entsel. Например, обработав "пустой" ввод (Enter без выбора объекта)
То, что надо! Спасибо.
Добавил маячок входа в видовой экран и выход при необходимости
Код:
[Выделить все]
 (setq opora (car (entsel "Выберите блок КС_Опора <Смена пространства>: ")))
        (if (null opora)
	  (progn
            (setq mayachok 1)
	    (vl-cmdf "_.MSPACE")
	    (setq opora (entsel "Выберите блок КС_Опора: "))
	    (if opora (setq opora (car opora)))
	  )
	)
Код:
[Выделить все]
 (if (= mayachok 1)
	    (vl-cmdf "_.PSPACE")
       )
Сыч вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > Лисп для записи свойств одно динамического блока в атрибуты другого блока

Vetcad
Размещение рекламы
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Тестирование динамического блока дает другой результат нежели вхождение Artem.jkl Динамические блоки 1 13.12.2019 00:58
Как блокировать атрибуты динамического блока? Leopard_ Динамические блоки 13 20.06.2019 10:42
Назначение свойств атрибутов блока без attsync Кулик Алексей aka kpblc Программирование 9 15.08.2017 06:32
Странное поведение динамического блока высотной отметки hwd Динамические блоки 12 08.09.2011 11:15
Изменение свойств атрибута в составе блока rzinnurov AutoCAD 9 24.04.2009 15:17