- •Утверждено
- •Программирование на языке AutoLisp
- •1. Переменные языка AutoLisp
- •1.1 Системные переменные пакета AutoCad
- •1.2 Переменные языка AutoLisp определенные пользователем
- •2. Типы данных языка AutoLisp
- •3. Функции присвоения
- •4.2 Работа со строками, функции преобразования, проверки типов данных.
- •4.3 Логические функции Автолиспа.
- •5. Работа со списками
- •6. Использование функции get для ввода данных.
- •7. Работа с геометрическими описаниями объектов
- •8. Условное ветвление программ
- •9. Организация циклов
- •10. Вызов команд Автокада из программы на языке AutoLisp
- •11. Управление отображением
- •12. Вывод данных в командную строку
- •13. Файловый ввод - вывод
- •14. Определение функции
- •15. Отладка программы.
- •16. Доступ к примитивам и средствам Автокада
- •Функции AutoLisp Математические функции
- •Логические функции Автолиспа.
- •Работа со списками
- •Использование функции get для ввода данных.
- •Работа с геометрическими описаниями объектов
- •Условное ветвление программ
- •Организация циклов
- •Вызов команд Автокада из программы на языке AutoLisp
- •Управление отображением
- •Вывод данных в командную строку
- •Файловый ввод - вывод
- •Доступ к примитивам и средствам Автокада
- •Insert (block)
- •Vertex (pline)
15. Отладка программы.
Если в тексте программы допущена ошибка то ее инициализация (load ...) будет прерва-на с сообщением в командной строке - *Cancel*. Как правило это указывает на неравен-ство количеств открывающих и закрывающих скобок () или кавычек “ “. Следует внимательно просмотреть программу и если ошибка не обнаружена то исключать строчки ее текста из компиляции проставляя символ ; (точка с запятой) в начале строки.
Если компиляция программы прошла успешно (в командной строке появилось имя функции) однако выполнение программы прерывается, то следует обнаружить место где это происходит. В этом случае можно также воспользоваться принципом исключением строчек текста программы с помощью символа ; (точка с запятой).
На этапе отладки программы не следует объявлять переменные как локальные тогда их последовательно можно просмотреть с командной строки (например: ! c_p или ! col) определяя тем самым место ошибки (т.е где прерывается присвоение значений переменным) в программе.
Наиболее универсальным средством обнаружения ошибок является простановка в тексте программы функций (alert сообщение). Данная функция приостанавливает выполнение программы, выводит в диалоговое сообщение и ждет нажатие пользователем кл. Enter или OK.
Например: (defun val()
- - - - - - - - - - - - -
- - - - - - - - - - - - - (alert ”Stop1”)
- - - - - - - - - - - - -
- - - - - - - - - - - - - (alert “Stop2”)
- - - - - - - - - - - - -
)
Если выполнение программы дойдет до второй строки, то последует сообщение Stop1, если до четвертой Stop2 и т.д.
(exit)
Данная функция немедленно прекращает выполнение программы.
Например: (defun cr_l()
(setq rad nil)
(setq rad (getdist"Enter value radius > 10\n"))
(if (< rad 10) (progn (princ "Error rad<10") (exit)))
(setq c_p (getpoint"Enter center point\n"))
(command "circle" c_p (- rad 10))
)
Если введенное пользователем значение rad меньше 10 то в командную строку выводится сообщение “Error rad<10” и выполнение программы прерывается.
16. Доступ к примитивам и средствам Автокада
Главной особенностью языка AutoLisp является то, что он позволяет осуществлять доступ к графической базе данных (ГБД) п.AutoCAD, т.е. его возможности можно использовать для работы с геометрическими примитивами чертежа.
Как вы уже знаете, любой создаваемый в Автокаде чертеж состоит из примитивов, геометрическое описание которых хранится в специальном формате (формате Автокада) в файле чертежа (расширение .dwg). При загрузке чертежа Автокад заполняет графическую базу данных: записывает системные настройки, создает список объектов и вносит в ГБД геометрическое описание этих объектов, присваивая каждому примитиву уникальное имя. Итак, в сеансе редактирования каждый примитив (отрезок, дуга, окружность и т.п.) имеет свое имя по которому его распознает сам Автокад. Эти имена меняются от одного сеанса редактирования к другому и поэтому нет смысла их запоминать. Однако можно в программе на AutoLISP сначала найти имя примитива в базе данных Автокада, с тем чтобы впоследствии непосредственно манипулировать геометрическими характеристиками примитива. Например, чтобы извлечь из ГБД имя последнего (last) построенного примитива (допустим отрезка прямой) в командной строки запишем: (setq ename (entlast))
Автокад возвращает например <Entity name: 60000A14>.
Тем самым мы присвоили переменной ename имя последнего объявленного примитива - точки, отрезка прямой, дуги, текста и т.д.. Напомним еще раз, что имена примитивов изменяются от сеанса к сеансу, и вы наверняка увидите на экране другое имя. Имена примитивов в Автокаде – шестнадцате-ричные величины и может быть например таким: 60000А14. Используя это имя, можно при помощи функции ENTGET получить доступ к данным, связанным с примитивом: (setq edata (entget ename))
Если это отрезок прямой то переменной edata будет присвоено значение:
((-1 . <Entity name 60000A14>) (0 . “LINE”) (8 . “LAYER1”) (10 16.22 84.25 0.0) (11 8.11 0.18 0.0) (210 0.0 0.0 1.0))
Имя примитива - это тип данных языка AutoLisp, и если функции ENTGET требуется имя примитива, то бесполезно указывать шестнадцатеричное число 60000А14 - надо передать значение переменной ename, в которой это имя хранится.
В языке AutoLisp, описание примитивов, представляют собой список, состоящий, в свою очередь, из подсписков, в которых сгруппированы по функциональному назначе-нию все данные о примитиве, как геометрические, так и общие: слой, цвет и т.п. Подсписки отличаются по специальным кодам формата DXF (Drawing eXchange Format - формат обмена рисунками), позволяющим определить, какой тип данных хранится в подсписке. Каждый подсписок имеет две части. Первая часть - код DXF, вторая - данные. Например для примитива “LINE” коды DXF -1 . - имя примитива, 0 . - тип примитива, 8 . - имя слоя, 10 - начальная точка примитива, 11 - конечная точка, 210 - направление выдавливания.
Следует обратить внимание что подсписки с кодами DXF -1 . , 0 . , 8 . , (структура кода : цифра-пробел-точка) являются списками типа “точечная пара”, которые нельзя получить функцией LIST. Такие списки необходимо получать с помощью функции QUOTE, например: (setq sp_t ‘(8 . “LAYER_ALL”))
Представим переменную список edata в виде таблицы:
Код DXF |
Данные |
Характеристика
|
-1. |
60000А14 |
Имя примитива |
0. |
“LINE” |
Тип примитива |
8. |
“LAYER1” |
Имя слоя которому принадлежит примитив |
10 |
16.22 84.25 0.0 |
Начальная точка отрезка |
11 |
8.11 0.18 0.0 |
Конечная точка отрезка |
210 |
0.0 0.0 1.0 |
Направление выдавливания (служебный код) |
Следовательно, пользуясь кодами DXF, можно извлечь из сложного списка edata любую информацию о примитиве. Такой доступ к рисунку более сложен, но предостав-ляет широкие возможности. Теперь можно программно изменять практически все свойства примитивов. Поэтому при работе со списками данных о примитивах важно знать кодировку кодов DXF. Значения DXF кодов основных примитивов даны в Приложении С.
Имена примитивов можно определять указанием точки принадлежащей примитиву, с помощью функции:
(entsel строка-подсказка)
Выбирается примитив, при этом выбор должен быть сделан указанием на примитив. Возвращается список, первый элемент которого - имя выбранного примитива, а второй - координаты точки в которой он был указан. Строка-подсказка используется для запроса примитива. Если она не указана, то выдается стандартный запрос "Select object:" (Выберите объект).
Например, для ранее определенного отрезка прямой функция ENTSEL
(setq ent1 (entsel))
присваивает переменной ent1 значение списка
( <Entity name 60000A14> ( 11 14.0 5.28 0.0))
где первый элемент списка - имя примитива <Entity name 60000A14>, а второй - (11 14.0 5.28 0.0) – код DXF и координаты точки лежащей на выбранном отрезке в которой он был указан. Присвоить имя примитива переменной ename, можно с помощью следуюшей конструкции:
(setq ename (car ent1))
Примитивы можно удалять из чертежа функцией ENTDEL:
(entdel ename)
В данном случае переменная ename - имя примитива. Этот способ позволяет удалять из ГБД также невидимые примитивы, что невозможно обычным выбором объектов (нельзя выбрать объект если он находится в отключенном слое). Следует отметить одну интересную особенность: функция ENTDEL вызванная повторно с тем же именем примитива, восстановит его в ГБД. Для получения DXF характеристик примитивов можно использовать конструкцию: (setq ent_p (entget (car (entsel))
Если в ответ на запрос функции entsel "Select object:" будет указан примитив то переменной ent_p будет присвоено значение сложного списка (типа edata).
(entnext имя_примитива)
При вызове без параметра имя_примитива, возвращает имя первого не удаленного примитива в ГБД. При задании имя примитива возвращает имя первого не удаленного примитива, следующего в ГБД за примитивом имя_примитива. Если примитива нет, возвращается nil. Возвращаются как основные примитивы, так и субпримитивы (например, вершины полилинии (VERTEX).
Например: (setq en1 (car (entsel))) - имя примитива POLYLINE
(setq en2 (entnext en1)) - далее следуют вершины полилинии (VERTEX)
(setq en3 (entnext en2))
Для модификации геометрических характеристик примитива непосредственно в ГБД надо уметь находить в DXF-списке данных примитива (например переменная EDATA) подсписки, в которых хранится нужная информация. Выбор и изменение различных данных, относящихся к примитиву, осуществляются по коду DXF (это всегда целое число) с помощью функций ASSOC и SUBST.
(assoc элемент_списка сложный_список)
Извлекает из сложного_списка элемент списка по ключу элемент_ списка. Если элемент_списка не найден ASSOC возвращает nil. С ее помощью можно извлечь, например, из списка edata
((-1 . <Entity name 60000A14>) (0 . “LINE”) (8 . “LAYER1”) (10 16.22 84.25 0.0) (11 8.11 0.18 0.0) (210 0.0 0.0 1.0)) список содержащий координаты начальной точки (код 10):
(setq edata_start (assoc 10 edata))
Переменная edata_start определяет подсписок (10 16.22 84.25 0.0).
В приведенном выше примере мы фактически сказали AutoLISP: "Возврати подсписок с DXF-кодом 10". Автолисп просмотрел DXF-список примитива, нашел подсписок с кодом 10 и возвратил его. Разумеется целиком. Полученный по коду подсписок edata_start, все еще содержит DXF-код 10, который можно убрать. Для этой цели лучше всего использовать функцию CDR:
(setq pp1 (cdr edata_start))
Переменная pp1 определяет список (16.22 84.25 0.0).
С помощью этой функции можно присвоить переменной имя слоя в котором находится примитив, например:
(setq lay (cdr (assoc 8 edata)))
Переменной lay присваивается символьное значение LAYER1
(subst новый элемент старый элемент список)
Возвращает копию исходного списка с заменой всех найденных подсписков, идентичных старому элементу, на новый элемент. Например, присвоим переменной p_start значение подсписка списка edata, содержащего координаты начальной точки отрезка прямой
так (setq p_start (assoc 10 edata))
или так (setq p_start (nth 3 edata))
Учитываем, что нумерация элементов списка начинается со значения 0. Тогдa: если
(setq edata_new (substr (list 10 22.4 35.16 0) p_start edata))
то переменная edata_new определит новый список
((-1. <Entity name 60000A14>) (0. “LINE”) (8. “LAYER1”) (10 22.4 35.16 0)
(11 8.11 0.18 0.0) (210 0.0 0.0 1.0)).
Если вхождений не обнаружено, SUBST возвращает копию старого списка.
Извлекая из DXF-списков нужную информацию, можно программно обрабатывать ее и затем, внеся изменения в DXF-список примитива при помощи функции SUBST, модифицировать ГБД при помощи функции ENTMOD:
(entmod список)
Эта функция (где переменная список - сложный список типа edata) обновляет информацию в ГБД. Следует иметь в виду, что функция ENTMOD не всесильна.
Во-первых, нельзя изменить тип примитива (если вы хотите сделать это, вам остаётся только удалить его с помощью функции ENTDEL и создать новый примитив с помощью функции COMMAND).
Во-вторых, все объекты, на которые ссылается список данных, должны быть известны Автокаду к тому моменту, когда вызывается функция ENTMOD (гарнитура шрифта, типы линий, имена форм и блоков и пр.). Исключением из этого правила является слой - если определённого в списке слоя нет, будет создан новый. Целые значения автомати-чески преобразуются в значения плавающей точкой. Например:
(setq lay_old (assoc 8 edata))
(setq lay_new ‘(8 . LAYER_ALL))
(setq edata_new (subst lay_new lay_old edata)
Переменная edata_new определяет новый примитив:
((-1 . <Entity name 60000A14>) (0 . “LINE”) (8 . “LAYER_ALL”)
(10 16.22 84.25 0.0) (11 8.11 0.18 0.0) (210 0.0 0.0 1.0))
(entmod edata_new)
Функция endmod изменяет характеристику отрезка прямой, находя его по имени (<Entity name 60000A14>) в ГБД, если слой LAYER_ALL в ней отсутствует то он создается.
Если обновляется не основной примитив, а "подпримитив" (вершина полилинии или атрибут блока), то для обновления изображения следует использовать функцию ENTUPD:
(entupd список)
Обновляет изображение “подпримитива” в ГБД и на экране.
Как уже говорилось, имена примитивов действительны лишь в текущем сеансе редак-тирования. Но в AutoLISP есть средство - метки, позволяющее узнавать примитивы из других сеансов. Метки - это просто номера примитивов в ГБД: они присваиваются автоматически в процессе создания примитивов, если были включены командой п. AutoCAD HANDLES. С ними можно работать из AutoLISP с помощью функции HANDENT:
(handent метка)
Возвращает имя примитива, который указывается строковым параметром метка. После того как получено имя примитива, оно может быть использовано для дальнейшей работы. Например если характеристика примитива опреде-лена сложным списком, в котором код DXF 5 . определяет метку примитива
((-1 . <Entity name 60000A14>) (0 . “LINE”) (8 . “LAYER_ALL”) (5 . “5А”) (16.22 84.25 0.0) (11 8.11 0.18 0.0) (210 0.0 0.0 1.0))
то функция
(setq ename (handent “5A”))
присвоит переменной ename значение <Entity name 60000A14>
Литература
1. Программирование на языке АВТОЛИСП в системе САПР АВТОКАД
С. А. Гладков “ДИАЛОГ-МИФИ” 1991г.
2. АВТОЛИСП версии 12. Руководство программиста.
Copyright 1990-92 Autodesk
ПРИЛОЖЕНИЕ А Список функций AutoLisp