Использование LISP для ассоциации параметров объектов nanoCAD BIM Строительство (конфигурация «Конструкции») и Платформы nanoCAD
У пользователей современных BIM-систем часто возникают задачи по автоматизации рутинных операций или по созданию какого-либо дополнительного функционала в рамках используемой BIM-системы. Как правило, для реализации таких задач используются средства автоматизации, работающие с API. В этой статье анализируется пример реализации дополнительного функционала с использованием языка LISP в nanoCAD BIM Строительство (конфигурация «Конструкции») (ранее – nanoCAD BIM Конструкции). Также описываемая далее LISP-утилита выполняет задачу, аналогичную команде ассоциации объектов (NBIM_ASSOCIATE), с той разницей, что LISP-утилита может синхронизировать параметры не только объектов nanoCAD BIM Строительство, но и объектов Платформы nanoCAD, и при этом без жесткой фиксации положения объектов относительно друг друга.
Автор статьи не является программистом по образованию и в тему программирования под LISP погрузился относительно недавно, поэтому приведенный далее код не является оптимальным и эталонным, но при этом может помочь таким же новичкам начать осваивать программирование под API. Также в ходе использования утилиты было решено множество задач:
- Описан пользовательский графический интерфейс на языке DCL и продемонстрирован прием загрузки DCL из LISP.
- Созданы реакторы, которые позволяют отслеживать изменения объекта, что в свою очередь позволило синхронизировать изменение ассоциированных объектов nanoCAD BIM Строительство (конфигурация «Конструкции») и примитивов Платформы nanoCAD.
- Отображать в пользовательском диалоге списка атрибутов доступных из COM-интерфейса объектов чертежа.
- Использовать методы COM-интерфейса объектов nanoCAD BIM Строительство (конфигурация «Конструкции») для обновления графики, записи и создания атрибутов.
Эта статья является продолжением ранее опубликованных материалов:
- Вебинара, посвященного теме программирования LISP под nanoCAD BIM Конструкции. На вебинаре можно найти различные ссылки на учебные материалы по LISP, а также советы по организации работы в средах программирования LISP.
- Статьи, посвященной связыванию параметров объектов nanoCAD BIM Конструкции. В ней описаны существующие способы синхронизации атрибутов объектов, а также сравнительный анализ описанных способов.
Описание COM-интерфейсов Платформы nanoCAD можно найти в документации из SDK. Получить SDK можно, зарегистрировавшись в клубе разработчиков на сайте developer.nanocad.ru.
По ссылке можно посмотреть блок-схему, которая описывает назначение пользовательских функций, созданных в LISP утилите.
Здесь приводится ссылка на видеодемонстрацию работы LISP-утилиты.
Учитывая, что описание синхронизации объектов и элементов пользовательского диалога должны соответствовать типам выбираемых объектов (примитивы Платформы nanoCAD и объекты nanoCAD BIM Строительство (конфигурация «Конструкции»)), первое, что нужно сделать – определить соответствующий тип объектов. Ниже приводится функция проверки наличия COM-свойства Element у vla-объекта.
(defun BIMneBIM (vlaobj)
(not
(vl-catch-all-error-p
(vl-catch-all-apply '(lambda (x) (vlax-get-property x "Element"))
(list vlaobj)
)
)
)
)
Функция возвращает Т, если выбран объект nanoCAD BIM Конструкции, и nil, если объект не относится к категории объектов nanoCAD BIM Конструкции.
Эта функция используется в диалоге выбора объектов, так как хотя бы один объект, выбранный пользователем, должен быть объектом nanoCAD BIM Строительство. Соответствующее условие проверяется в диалоге выбора.
(defun MAX_ASSOCIATE (/ vlaobj1 vlaobj2 obj1 ojb2)
(setq obj1 (car (entsel "\nВыберете первый объект")))
(setq vlaobj1 (vlax-ename->vla-object obj1))
(if (= nil (BIMneBIM vlaobj1))
(progn
(while (= nil (BIMneBIM vlaobj2))
(setq obj2 (car (entsel "\nВыберете второй объект, он должен быть объектом BIM Конструкции")))
(setq vlaobj2 (vlax-ename->vla-object obj2))
)
)
(progn
(setq obj2 (car (entsel "\nВыберете второй объект")))
(setq vlaobj2 (vlax-ename->vla-object obj2))
)
)
(Dialog vlaobj1 vlaobj2)
)
Далее выбранные объекты передаются для формирования окна пользовательского диалога, который описан на DCL. Объекты необходимы для формирования списков атрибутов, которые отображаются в диалоговом окне, а также для определения поведения этого окна в зависимости от типа выбранных объектов.
Для создания пользовательского диалога необходимо описать окно интерфейса. Описание выполнено с помощью DCL. Есть пользовательский прием, который позволяет упростить работу с файлом интерфейса: файл DCL интерфейса создается из кода LISP (источник: https://autolisp.ru/2015/02/05/dcl-develop/). Это упрощает передачу таких утилит, так как можно передать лишь один файл *.lisp, в котором будет код утилиты и графический интерфейс.
(defun fun_create-dcl-file (file / handle)
;получение дескриптора
(setq handle (open file "w") ;создание переменной handle с номером дескриптора файла.
) ;_ end of setq
(foreach item
'(;построчная запись в файл нижележащих стрингов
"ParamSpis: dialog {label=\"Список параметров объекта\";" ":row {"
":boxed_column {label=\"Список параметров первого объекта\";"
":spacer {height=3;}"
":button { label=\"Заголовок/Имя\"; key=\"k1\"; fixed_width=true; width=14; alignment=left; }"
":list_box {label=\"\"; key=\"b1\";"
"list=\"\"; width = 50; height = 50; aligment=\"right\"; fixed_width=true; fixed_width_font=True;}"
"}// column"
":boxed_column { label=\"Направление передачи и пересчет значения\";"
":spacer {height=25;}"
":button {label=\"Направление передачи\"; key=\"k3\"; height=3; width=20;}"
":text {label=\"\"; fixed_width=true; width=6; height = 4; alignment=left; value=\"----->\"; key=\"k4\"; }"
":text {label = \"Перерасчет значения\"; key=k5;}"
":text {label = \"Синтаксис должен соответствовать Мастеру функций\"; key=k52;}"
":edit_box { label=\"\"; key=\"k6\"; width=60; value = \"\";}"
":spacer {height=25;}" "}"
":boxed_column { label=\"Список параметров второго объекта\";"
":spacer {height=3;}"
":button { label=\"Заголовок/Имя\"; key=\"k2\"; fixed_width=true; width=14; alignment=left;}"
":list_box {label=\"Список параметров 2-ого выбранного объекта\"; key=\"b2\";"
"list=\"\"; width = 50; height = 50; aligment=\"left\"; fixed_width=true; fixed_width_font=True;}"
"}// column" "}// row" ":spacer {height=1;}" "ok_button;" "}"
)
(write-line item handle)
) ;_ end of foreach
(close handle)
file
)
Функция создания файла интерфейса вызывается внутри диалога.
(defun Dialog (obj1 obj2 / dcl_id listik2 listik1 str1 str2 bool bool1 bool2 zero)
;создание списка параметров объекта obj1 и obj2
(setq zero (list
(cons "obj1"
(if (= nil (BIMneBIM obj1))
(progn
(setq Obj1BimNot "Obj1NeBim")
(ParamListNeBIMS obj1)
)
(progn
(setq Obj1BimNot "Obj1Bim")
(paramlist obj1)
)
)
)
(cons "obj2"
(if (= nil (BIMneBIM obj2))
(progn
(setq Obj2BimNot "Obj2NeBim")
(ParamListNeBIMS obj2)
)
(progn
(setq Obj2BimNot "Obj2Bim")
(paramlist obj2)
)
)
)
)
)
;проверка наличия файла временного диалога dcl
(setq file (strcat (vl-string-right-trim "\\" (getenv "tmp")) "\\spiskop.dcl"))
(if (= nil (findfile file)) (fun_create-dcl-file file)) ; если файл не найден, он создается.
;загрузка диалога
(if (< (setq dcl_id (load_dialog file)) 0) (exit))
(if (not (new_dialog "ParamSpis" dcl_id)) (exit))
;первоначальная загрузка в List_box-ы списков параметров с именами
(Podpersis "b1" "Имя" "obj1" zero)
(Podpersis "b2" "Имя" "obj2" zero)
(setq bool2 0)
(setq listik1 (cdr (assoc "Имя" (car (cdr (assoc "obj1" zero))))))
(setq listik2 (cdr (assoc "Имя" (car (cdr (assoc "obj2" zero))))))
(cond
((and (= "Obj2Bim" Obj2BimNot) (= "Obj1Bim" Obj1BimNot)) ; Обработка диалога в зависимости от того, чем являлись исходные объекты. Объекты nanoCAD BIM Конструкции или все прочие объекты.
(progn ;обработка диалога так, если бы оба объекта были MS-ные или BIM-овские
(action_tile "k3"
"(setq bool2 (Strelka bool2 str1 str2))"
)
;Действия которые передается в пользовательский диалог при выборе соответствующих значений в интерфейсе
(action_tile "b1"
"
(setq str1 $Value)
(if(= bool2 0)(set_tile \"k6\" (Nameparam listik1 str1)))
"
)
(action_tile "b2"
"
(setq str2 $Value)
(if(= bool2 1)(set_tile \"k6\" (Nameparam listik2 str2)))
"
)
(action_tile "k1"
"(setq bool (Perspis bool \"b1\" zero \"obj1\"))"
)
(action_tile "k2"
"(setq bool1 (Perspis bool1 \"b2\" zero \"obj2\"))"
)
) ;progn
) ;1ое условие
((and (= Obj1BimNot "Obj1NeBim") (= Obj2BimNot "Obj2Bim"))
(progn ;обработка диалога для случая когда первый выбранный объект является объектом платформы
(mode_tile "k3" 1)
(mode_tile "k1" 1)
(set_tile "k4" "----->")
(setq bool2 1)
(action_tile "b1"
"
(setq str1 $Value)
(if(= bool2 1)(set_tile \"k6\" (Nameparam listik1 str1)))
"
)
(action_tile "b2"
"
(setq str2 $Value)
"
)
(action_tile "k2"
"(setq bool1 (Perspis bool1 \"b2\" zero \"obj2\"))"
)
) ;progn
) ;2ое условие
(T
(progn ;обработка диалога для случая, когда второй выбранный объект является объектом платформы
(mode_tile "k3" 1)
(mode_tile "k2" 1)
(set_tile "k4" "<-----")
(setq bool2 0)
(action_tile "b1"
"
(setq str1 $Value)
"
)
(action_tile "b2"
"
(setq str2 $Value)
(if(= bool2 0)(set_tile \"k6\" (Nameparam listik2 str2)))
"
)
(action_tile "k1"
"(setq bool (Perspis bool \"b1\" zero \"obj1\"))"
)
) ;progn
) ;краянее условие
) ;cond
;Окончание диалога. И чтение из text_box имени\формулы параметра для которого будет выполняться вычисление при последующей его передачи в объект BIM Конструкции / Model Studio CS
(action_tile "accept"
"(setq formula (get_tile \"k6\"))
(done_dialog)"
)
(start_dialog)
(unload_dialog dcl_id)
;вырезка имени из строки списка параметров по номеру выбранной строки в интерфейсе
(setq str1 (Nameparam listik1 str1))
(setq str2 (Nameparam listik2 str2))
;передача вырезанных имен и списков параметров
(if (and (= "Obj2Bim" Obj2BimNot) (= "Obj1Bim" Obj1BimNot))
(progn ;оба объекта BIM Конструкций
(if (= bool2 1)
(progn
(sinhr
str2
str1
(cdr (assoc "obj2" zero))
(cdr (assoc "obj1" zero))
obj2
obj1
formula
)
)
(progn
(sinhr
str1
str2
(cdr (assoc "obj1" zero))
(cdr (assoc "obj2" zero))
obj1
obj2
formula
)
)
)
)
(progn ;один из объектов не BIM Конструкций
(if (and (= Obj1BimNot "Obj1NeBim") (= Obj2BimNot "Obj2Bim"))
(progn ;первый объект не BIM конструкций.
(sinhr2 str1 str2 (cdr (assoc "obj2" zero)) obj1 obj2 formula)
)
(progn ;Второй объект не BIM конструкций.
(sinhr2 str2 str1 (cdr (assoc "obj1" zero)) obj2 obj1 formula)
)
)
)
)
)
В диалоговом окне используются другие вспомогательные функции, они описаны на блок-схеме, ссылка на которую есть в начале статьи. А теперь подробнее рассмотрим функции, которые позволяют загрузить в диалоговое окно список параметров объектов.
Список параметров для объектов nanoCAD BIM Строительство и примитивов Платформы nanoCAD формируется по-разному:
- у объектов nanoCAD BIM Строительство (конфигурация «Конструкции») параметры выгружаются из списка параметров главного узла свойств object.Element.Parameters. Поскольку почти у всех объектов nanoCAD BIM Строительство (конфигурация «Конструкции») такая структура хранения атрибутов, достаточно описать одну функцию выгрузки для объектов nanoCAD BIM Конструкции;
- у объектов Платформы nanoCAD в COM нет отдельного свойства со списком параметров. Однако в LISP существует перечень функций, которые позволяют получить свойства из COM-интерфейса. Есть пользовательский прием, который позволяет получить список свойств объекта с помощью циклического перебора функций, запрашивающих свойства из COM-интерфейса объекта (https://www.caduser.ru/forum/post262232.html#p262232).
Рассмотрим код, который запрашивает список свойств объектов nanoCAD BIM Строительство (конфигурация «Конструкции»).
;Функция, которая через COM достает список параметров объектов BIM Конструкции. Список формируется в виде двумерного листа.
;Где первый лист отформатированный список "ИмяПараметра=Значение", и он необходим для вывода в диалог.
;А второй лист аналог словаря с ключом по имени параметра.
;Возвращаемое значение функции имеет вид ((List форматированный список)(ИмяПараметра(Остальные поля параметров)))(Имя параметра.(list значение заголовок комментарий)).
(defun ParamList (obj / VlObj Elm Param_List Count_Param_List List_Param_List vla_par
ParName ParValue FrmtParamList1 FrmtParamList2 i
)
(setq Elm (vlax-get-property obj "Element"))
(setq Param_List (vlax-get-property Elm "Parameters"))
(setq Count_Param_List (vlax-invoke-method Param_list "Count"))
(setq List_Param_List (list))
(setq i 0)
(while (< i Count_Param_List)
(setq vla_par (vlax-invoke-method Param_List "item" i))
(setq ParName (vlax-get-property vla_par "Name"))
(setq ParValue (vlax-get-property vla_par "Value"))
(setq Zagolovok (vlax-get-property vla_par "Comment"))
(setq Comment (vlax-get-property vla_par "ValueComment"))
(setq List_Param_List (cons (list ParName (list ParValue Zagolovok Comment))
List_Param_List
)
)
(setq FrmtParamList1 (cons (strcat ParName " = " ParValue) FrmtParamList1))
(setq FrmtParamList2 (cons (strcat Zagolovok " = " ParValue) FrmtParamList2))
(setq i (1+ i))
)
(setq List_Param (list
(list (cons "Имя" (acad_strlsort FrmtParamList1))
(cons "Заголовок" (acad_strlsort FrmtParamList2))
)
List_Param_List
)
)
)
Таким образом, возвращаемый список параметров хранит пары значений: заголовок и значение, имя и значение. Это необходимо для переключения варианта отображения в окне пользовательского диалога (рис. 1).
Рис. 1. Кнопки изменения отображения Заголовок/Имя
Рассмотрим код функции ParamListNeBIMS, которая запрашивает список свойств объектов Платформы nanoCAD.
(defun ParamListNeBIMS (vlaobj / rezlist)
(setq vlaobj (list vlaobj) ;Cоздание на основе VLAObj списка состоящего из одного элемента. Это необходимо, чтобы потом отработала функция vl-catch-all-apply
rezlist nil ;очистка переменной
)
(mapcar
(lambda (x / prop); объявление лямбда функции, у которой в качестве аргумента приходит почищенный atoms-family
(if ;Проверка через два условия наличия свойства и его значения. 1-ое условие проверяет через функцию vlax-property-available-p, что свойство есть у объекта. 2-ое условие проверяет возможность чтения значения проверяемого свойства.
(and
(vlax-property-available-p ;Проверяет, имеет ли объект данное свойство. (vlax-property-available-p <объект> <свойство> [<модификация>]) Возвращаемое значение — T или nil
(car vlaobj) ;получение vla-объекта
(vl-string-subst "" "VLA-GET-" x) ;из ранее обработанного списка atoms family, из которого удалили все элементы списка кроме тех, что начинаются на vla-get, берется элемент списка в виде строки с вычитанием подстроки vla-get
)
(not ;проверка отсутствия ошибки при попытке получения значения свойства
(vl-catch-all-error-p ;Проверяет, является ли объект, возвращенный функцией vl-catch-all-apply, объектом типа VL-CATCH-ALL-APPLY-ERROR. (vl-catch-all-error-p <аргумент>) Тип аргумента — любой. Возвращаемое значение: T, если <аргумент> относится к объектам типа VL-CATCH-ALL-APPLY-ERROR, и nil, если <аргумент> имеет другой тип.
(setq prop (vl-catch-all-apply ;Передает для выполнения указанной функции список в качестве аргументов и дает возможность обработать прерывание, связанное с ошибкой. (vl-catch-all-apply '<функция> <список>)
;Возвращаемое значение — результат применения функции <функция> к списку <список> Возвращаемое значение — результат применения функции <функция> к списку <список>.
;В данном случае выполняется попытка получение значения свойства VLA-GET-... у объекта vlaobj, который передается как список. Вместо ... подразумеваются перебираемые варианты, например VLA-GET-COLOR, VLA-GET-NAME и т.п.
(read x)
vlaobj
)
)
)
)
)
(setq rezlist (cons (strcat (vl-string-subst "" "VLA-GET-" x) " = " (Preobr x prop)) rezlist) ;добавление в rezlist имени успешно отработавшего VLA-GET-... и свойства которое по нему получено
)
)
)
(vl-remove-if-not ;Удаляет из списка все элементы, возвращающие nil при проверке тест-функцией. (vl-remove-if-not '<тест-функция> <список>)
'(lambda (x) (vl-string-search "VLA-GET-" x)) ;поиск элементов списка atoms-family, которые начинаются на "VLA-GET-"
(atoms-family 1) ;возвратит список зарезервированных символов
)
)
(setq rezlist (list (list (cons "Имя" (acad_strlsort rezlist)) (cons "Заголовок" (acad_strlsort rezlist))) rezlist))
)
Источник: https://www.caduser.ru/forum/post262232.html#p262.
Функция ParamListNeBIMS проверяет наличие в COM-интерфейсе свойств, которые можно получить в соответствии со спецификацией языка LISP. Все полученные таким образом свойства передаются в качестве возвращаемого значения. В функции ParamListNeBIMS также используются подфункции Preobr и ObjName, которые приводят к строке все типы получаемых значений свойств, даже в том случае, когда возвращаемым типом является VLA-объект. К строке приводится имя VLA-объекта. Далее следует код подфункции Preobr.
;подфункция преобразования в строку данных полученных в COM свойствах
(defun Preobr (x prop)
(cond
((= (type (car vlaobj)) (type prop))
(strcat "Vla-объект: " (ObjName prop))
)
((numberp prop)
(setq prop (rtos prop 2 3))
)
((= prop :vlax-false)
"Ложь"
)
((= prop :vlax-true)
"Истина"
)
((= (type prop) (type (vlax-make-variant nil)))
(vl-princ-to-string (vlax-safearray->list (vlax-variant-value prop)))
)
((= prop nil)
"Пусто"
)
(T
(vl-princ-to-string prop)
)
)
)
;Функция получения имени vla-объекта, даже в том случае, когда у объекта нет свойства objectname.
(defun ObjName (prop)
(setq stroka (vl-princ-to-string prop))
(setq nachalovich (+ 2 (vl-string-search " " stroka)))
(setq NachPoisVtorProb (+ 1 (vl-string-search " " stroka)))
(setq kolvoSimvl (- (+ 1 (vl-string-search " " stroka NachPoisVtorProb))
nachalovich
)
)
(substr stroka nachalovich kolvoSimvl)
)
А теперь рассмотрим подфункции dialog, которые вызывают интерфейс и описывают взаимодействие пользователя с ним. Код функции Strelka отвечает за изменение направления передачи параметра.
(defun Strelka (bool2 st1 st2)
(if (= bool2 0)
(progn
(set_tile "k4" "<-----")
(set_tile "k6" (Nameparam listik2 st2))
(setq bool2 1)
)
(progn
(set_tile "k4" "----->")
(set_tile "k6" (Nameparam listik1 st1))
(setq bool2 0)
)
)
)
Эту функцию активирует нажатие кнопки Направление в интерфейсе программы. В соответствии с изменением направления передачи синхронизируемого атрибута в диалоговом окне меняется направление стрелки и имя параметра в поле пересчета значения. В этом поле указано имя параметра, значение которого передается от ведущего объекта к ведомому (рис. 2-3). В случае, если один из объектов является примитивом Платформы nanoCAD, кнопка направления становится неактивной, а значение параметра передается от примитива платформы к объекту nanoCAD BIM Строительство (конфигурация «Конструкции») (рис. 4).
Рис. 2. Направление передачи от первого объекта ко второму
Рис. 3. Направление передачи от второго объекта к первому
Рис. 4. Передача параметра от примитива к объекту nanoCAD BIM Строительство (конфигурация «Конструкции»)
В описанной выше функции Strelka используется подфункция Nameparam, которая возвращает имя параметра, которое выбрано пользователем в списке параметров объекта. Возвращаемое значение устанавливается в поле пересчета значения.
(defun Nameparam (listik str)
(If (/= str nil)
(progn
(substr (nth (atoi str) listik) 1 (vl-string-search " = " (nth (atoi str) listik))
)
)
(progn "")
)
)
Рис. 5. Передача имени параметра из списка в поле пересчета
Функция Perspis выполняется при нажатии кнопки смены отображения Заголовок/Имя (рис. 1).
(defun Perspis (bool Key_obj lister objer)
(if (= bool 0)
(progn
(Podpersis Key_obj "Имя" objer lister)
(setq bool 1)
)
(progn
(Podpersis Key_obj "Заголовок" objer lister)
(setq bool 0)
)
)
)
В зависимости от режима отображения в интерфейсе появляется ранее сформированный функцией ParamList список значений. Если в интерфейсе выводится список параметров примитива Платформы nanoCAD, кнопка переключения режима отображения неактивна (рис. 6), так как только у объектов nanoCAD BIM Строительство (конфигурация «Конструкции») в параметрах есть заголовок и имя.
Рис. 6. Неактивная кнопка переключения Заголовок/Имя у примитива Платформы nanoCAD
После обработки диалогового окна данные о синхронизируемых атрибутах передаются в соответствующие функции синхронизации sinhr и sinhr2. Возможны два варианта типов синхронизируемых объектов, поэтому функций синхронизации тоже две.
Функция sinhr синхронизирует параметры двух объектов nanoCAD BIM Строительство (конфигурация «Конструкции»).
;Функция, которая обеспечивает синхронизацию параметров, когда оба объекта являются объектами MS или BIM Конструкции
(defun sinhr (Name1 Name2 List_Par1 List_Par2 obj1 obj2 formula / VlObj handle
vla_elm vla_elm2 vla_prop vla_prop2 vla_par vla_par2 handle2 VlObj2
)
;Создание в комментарии COM выражения, которое копирует значения с объекта
(setq handle (VLA-GET-HANDLE obj1))
(setq vla_elm (vlax-get-property obj2 "Element"))
(setq vla_prop (vlax-get-property vla_elm "Parameters"))
(vlax-invoke-method vla_prop "SetParameter" "HANDLE_MAN" handle
"ID связывоемого объекта" ""
)
(vlax-invoke-method vla_prop
"SetParameter"
name2
""
(nth 1 (car (cdr (assoc Name2 (nth 1 List_Par2)))))
(strcat "=var perem := application.ActiveDocument.HandleToObject([HANDLE_MAN]).Element.Parameters.Item("
(chr 34)
name1
(chr 34)
").Value; \n"
(Strzam formula name1)
)
)
;Создание в комментарии COM выражения, которое обновляет графику объекта, на который скопирован параметр
(setq handle2 (VLA-GET-HANDLE obj2))
(setq vla_elm2 (vlax-get-property obj1 "Element"))
(setq vla_prop2 (vlax-get-property vla_elm2 "Parameters"))
(vlax-invoke-method vla_prop2 "SetParameter" "HANDLE_MAN" handle2
"ID связываемого объекта" ""
)
(setq objname (vla-get-objectname obj2))
(setq katob (or
(= objname "irnAxis")
(= objname "msConcreteBeam")
(= objname "msConcreteColumn")
)
)
(if (= katob T)
(vlax-invoke-method vla_prop2
"SetParameter"
"PARAM_UPDATE"
""
"Параметр для обновления графики"
(strcat "=application.ActiveDocument.HandleToObject([HANDLE_MAN]).ScaleEntity("
(chr 34)
"0,0,0"
(chr 34)
", "
(chr 34)
"1"
(chr 34)
")"
)
)
(vlax-invoke-method vla_prop2
"SetParameter"
"PARAM_UPDATE"
""
"Параметр для обновления графики"
(strcat "=application.ActiveDocument.HandleToObject([HANDLE_MAN]).UpdateGraphics")
)
)
(princ)
)
Функция sinhr создает в ведущем объекте два новых параметра: ID связываемого объекта и параметр для обновления графики (рис. 7). Под ведущим подразумевается объект, с которого копируется значение синхронизируемого параметра.
Рис. 7. Параметры, создаваемые в ведущем объекте
В ID связываемого объекта присваивается значение handle ведомого объекта. Handle – это уникальный для этого чертежа ID объекта. С его помощью через COM-интерфейс можно обращаться к конкретному объекту. В этом случае именно так и происходит, поскольку значение handle используется в формуле параметра для обновления графики (рис. 8). Формула содержит COM-запрос для обновления графики ведомого объекта. Таким образом, при изменении ведущего объекта активируется COM-запрос для обновления графики ведомого объекта, что позволяет избежать ручного обновления графики объектов при их синхронизации.
Рис. 8. Формула параметра для обновления графики
В ведомом объекте также создается дополнительный ID связываемого объекта. Также создается формула, которая была указана в списке параметров ведомого объекта (рис. 9). В него копируется значение соответствующего параметра из ведущего объекта.
Рис. 9. Параметры, создаваемые в ведомом объекте
ID связываемого объекта содержит значение handle ведущего объекта, с его помощью ведомый объект обращается к ведущему и получает значение синхронизируемого атрибута.
Формула, создаваемая в ведомом объекте, содержит COM-обращение к ведущему объекту с помощью handle (рис. 10).
Рис. 10. Формула ведомого объекта, копирующая значение с ведущего объекта
Также в формуле учитывается пересчет значения: формула пересчета задается в окне пользовательского интерфейса (рис. 11).
Рис. 11. Пересчет значения по формуле из пользовательского интерфейса
Функция sinhr2 синхронизирует изменения атрибутов примитива Платформы nanoCAD и nanoCAD BIM Строительство (конфигурация «Конструкции»).
;Функция, которая присваивает параметры для обеспечения синхронизации параметров, для случая когда один из объектов не является объектом MS или BIM Конструкции
(defun sinhr2 (Name1 Name2 List_Par2 obj1 obj2 formula / VlObj vla_elm vla_prop
handle handle2 spisreakc txtspisreakc
)
;Создание в комментарии COM выражения, которое копирует значения с объекта
(setq handle (VLA-GET-HANDLE obj1)) ;obj1 - объект не BIM конструкций
(setq vla_elm (vlax-get-property obj2 "Element"))
(setq vla_prop (vlax-get-property vla_elm "Parameters"))
(vlax-invoke-method vla_prop "SetParameter" "HANDLE_MAN" handle
"ID связываемого объекта" ""
)
(vlax-invoke-method vla_prop
"SetParameter"
name2
""
(nth 1 (car (cdr (assoc Name2 (nth 1 List_Par2)))))
(strcat "=var perem := application.ActiveDocument.HandleToObject([HANDLE_MAN])."
name1
"; \n"
(Strzam formula name1)
)
)
;создание реактора, который будет обновлять графику объекта MS или BIM Кон при изменении примитива.
(setq handle2 (VLA-GET-HANDLE obj2))
(setq spisreakc (mapcar (lambda (x) (vlr-reactions x))
(vlr-get-reactors-for-object obj1)
)
) ;получение списка реакций объекта
(foreach x spisreakc
(setq txtspisreakc (cons (vl-princ-to-string x) txtspisreakc))
) ;преобразование списка реакций в список строк
(setq reakc "((:VLR-MODIFIED . OBNOVOBJ) (:VLR-ERASED . STIROBJ) (:VLR-UNERASED . VOSTOBJ))") ;Список реакций в виде строки
(if (= nil (member reakc txtspisreakc)) ;проверка есть ли в назначенных объекту реакторах какой-либо, у которого в списке реакций имеется ранее назначенный список реакций этого LISP. Если есть, то реактор не назначаем. Если нет, то назначаем реактор.
(setq MyReac (vlr-object-reactor (list obj1)
handle2
(list '(:vlr-modified . Obnovobj)
'(:vlr-erased . StirObj)
'(:vlr-unerased . VostObj)
)
)
)
(vlr-pers MyReac)
)
(princ)
)
В функции sinhr2 ведомому объекту (объекту nanoCAD BIM Строительство (конфигурация «Конструкции»)) присваивается ID связываемого объекта, который содержит handle ведущего объекта (примитива Платформы nanoCAD). Формула, создаваемая в ведомом объекте, содержит COM-запрос к ведущему объекту с помощью handle (рис. 12).
Рис. 12. Параметры, создаваемые в ведомом объекте nanoCAD BIM Строительство (конфигурация «Конструкции»)
ID связываемого объекта содержит handle примитива платформы. Значение handle используется в формуле, которая считывает значение с примитива платформы (рис. 13).
Рис. 13. Формула COM-запроса, которая возвращает значение параметра примитива
Однако в отличие от sinhr в этом случае ведущему объекту нельзя задать формулу обновления геометрии ведомого объекта, так как ведущий объект всегда является примитивом Платформы nanoCAD и соответственно в нем нет функционала nanoCAD BIM Строительство (конфигурация «Конструкции») по созданию вычисляемых параметров. Решением в этом случае являются реакторы, которые позволяют расширить варианты поведения объектов. Спецификация языка LISP содержит конечный перечень реакторов, которые срабатывают при определенных событиях. Например, есть реактор событий изменения рисунка (vlr-acdb-reactor), который активирует события, связанные с добавлением, изменением, удалением примитива. В случае если происходит какое-либо событие для реактора, он запускает пользовательскую функцию. Таким образом, можно описывать дополнительное поведение объектов и САПР в зависимости от событий, происходящих во время работы над чертежом.
В функции sinhr2 создается реактор примитива (ведущего объекта) с реакциями на три события: изменение (Obnovobj), удаление (StirObj), восстановление (VostObj).
Для каждого из этих событий описана пользовательская функция, которая выполняется в случае происхождения такого события.
(defun StirObj (vlao reac args /)
(print "Меня стёрли! Я удаляю свои реакторы")
(foreach x (vlr-get-reactors-for-object vlao)
(vlr-pers-release x)
(vlr-remove x)
)
)
(defun VostObj (vlao reac args /)
(print "Меня восстановили! Я возвращаю свои реакторы")
(foreach x (vlr-get-reactors-for-object vlao) (vlr-add x) (vlr-pers x))
)
(defun Obnovobj (vlao reac args /)
(setq obj (vla-HandleToObject (vla-get-activedocument (vlax-get-acad-object))
(vlr-data reac)
)
)
(vlax-invoke-method obj "updategraphics")
)
Функция StirObj активируется в случае удаления примитива и удаляет его реакторы, а также выводит соответствующее уведомление в командную строку.
Функция VostObj активируется в случае восстановления примитива и восстанавливает реакторы примитива, а также выводит соответствующее уведомление в командную строку.
Функция Obnovobj активируется в случае изменения примитива и через COM вызывает обновление объекта nanoCAD BIM Строительство (конфигурация «Конструкции»).
Описанная утилита навряд ли имеет практическое применение в повседневном использовании, однако, отдельные продемонстрированные приемы могут быть использованы в других автоматизациях. Например, можно улучшить механизм создания металлопроката по полилинии/отрезкам, чтобы создаваемый металлопрокат ассоциировался с полилинией/отрезком, в этом случае изменение исходных примитивов изменяло бы элементы металлопроката.
Использование дополнительных средств автоматизации позволяет ускорить и упростить работу инженера-проектировщика, особенно когда это касается сложных и комплексных BIM-систем. Программные продукты линейки nanoCAD к таким системам относятся. В этой статье была описана лишь небольшая часть возможностей автоматизации с использованием API. Если приложить немного усердия, то с помощью nanoCAD любую рутину можно превратить в решение увлекательных задач.
О компании «Нанософт»
«Нанософт» – российский разработчик инженерного ПО: технологий автоматизированного проектирования (CAD/САПР), информационного моделирования (BIM/ТИМ) и сопровождения объектов промышленного и гражданского строительства (ПГС) на всех этапах жизненного цикла, а также сквозной цифровизации всех процессов в производстве. Флагманский продукт – Платформа nanoCAD – универсальная САПР для создания чертежей и 3D-моделей с прямой поддержкой *.dwg-формата.
О компании «Макссофт-24»
ООО «Макссофт-24» — авторизованный партнёр крупнейших российских разработчиков программного обеспечения и поставщиков широкоформатного оборудования.
Мы являемся Премьер и Фокус-партнёром компании «Нанософт разработка», что подтверждает высокий уровень экспертизы по линейке решений nanoCAD. Мы всегда находимся с разработчиком в прямом контакте для оперативного и компетентного решения Ваших задач.
Более 30 лет мы занимаемся комплексной интеграцией в инфраструктуру организаций различного масштаба ИТ-решений широкого функционального назначения: общесистемный софт, САПР и ТИМ, информационная безопасность, прикладное ПО, электронный документооборот, ЭЦП.
О nanoCAD BIM Строительство
nanoCAD BIM Строительство – BIM/ТИМ-решение на Платформе nanoCAD для проектирования в *.dwg-среде архитектурного и конструкторского разделов зданий/сооружений.
Продукт может использоваться в следующих конфигурациях:
- nanoCAD BIM Строительство – для проектирования разделов КР (КМ, КЖ и КД) и АР;
- nanoCAD BIM Архитектура – для проектирования раздела АР;
- nanoCAD BIM Конструкции – для проектирования раздела КР (КМ, КЖ и КД).