Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
METHOD / Основы САПР / AutoLISP2006.doc
Скачиваний:
86
Добавлен:
05.03.2016
Размер:
1.04 Mб
Скачать

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

Соседние файлы в папке Основы САПР