Урок 4. Программирование на языке AutoLISP

 

Предварительно ознакомьтесь с описанием языка AutoLISP



1.          Переменные. 1

2.          Работа с системными переменными. 2

3.          Функции AutoLISP. 4

4.          Операторы условия, циклы и работа со списками. 5

5.          Оформление процедуры.. 7

6.          Отладка кода. 8

7.          Упражнения. 9

 

1.   Переменные

 

Переменные — это символьные имена, которыми можно оперировать в программе. Переменным можно присваивать значения непосредственно в командной строке:

1.      (setq pt 7)             переменной pt присвоено значение 7;

2.      (setq colorRed”)            строковой переменной color присвоено значение «Red».

При использовании переменной в параметрах команды перед ней нужно поставить восклицательный знак.

 

Задание 4.1

Создать переменные pt1,pt2 координат двух точек и с их помощью построить отрезок. Создать строковую переменную color с обозначением цвета “Red” и закрасить отрезок.

 

Приведем протокол операций выполнения этого задания.

 

Command: (setq pt1 "2,2")à                                   "2,2"

Command: (setq pt2 "12,2")à                                 "12,2"

Command: (setq color "Red")à                   "Red"

Command: _line Specify first point: !pt1à   "2,2"

Specify next point or [Undo]: !pt2à            "12,2"

Specify next point or [Undo]: Ã*Cancel*

Command: chpropÃ

Select objects: 1 found

Select objects: Ã

Enter property to change [Color/LAyer/LType/ltScale/LWeight/Thickness/Material]: cÃ

New color [Truecolor/COlorbook] <BYLAYER>: !colorÃ

"Red"

 

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

Глобальные переменные доступны всем функциям AutoLISP, которые загружены в чертеж. Их значения доступны в проекте и после завершения той программы, в которой они объявлены. Любая переменная, которая специально не объявлена локальной, является глобальной. В глобальной переменной можно хранить константы, промежуточные значения вычислений, результирующие данные. Однако трудно уследить, какое значение ей присвоено в данной функции и не изменено ли оно другой функцией. Поэтому следует избегать введения глобальных переменных. Рекомендуется имена глобальных переменных отмечать справа и слева звездочками: *Global1* и документировать их.

 

Задание 4.2

Создать и протестировать локальные и глобальные переменные.

 

1.      Откройте новый чертеж. Закройте все другие чертежи. Откройте редактор Visual LISP.

2.      В окне CONSOLE введите строку кода (defun local-var (/ var1). Завершите ее нажатием клавиш CTRL+ENTER. Это даст возможность ввести вторую строку: (setq var1 “I am a local var))Ã.Таким образом вы определили функцию local-var. В теле этой функции объявлена локальная переменная var1 и ей присвоено значение текстового литерала.

3.      Для тестирования, т.е. проверки присвоенных значений переменным и функциям, нужно просто набрать их имя в строке окна консоли. В ответ получим текущие значения этих величин. Наберите var1Ã. В окне появится ответ nil — текущее значение переменной недоступно. Наберите local-varÃ. В окне появится ответ I am a local var. В функции local-var текущее значение переменной var1 определено.

4.      Определите var1 как глобальную переменную. Для этого ее надо объявить не внутри функции, а вне ее. Поэтому просто наберите код (setq var1 “I am a global var).

5.      Проверьте текущее значение переменной величины var1. Наберите в окне консоли var1. В ответ получите I am a global var. Значение глобальной переменной сохраняется. А теперь снова наберите (local-var)Ã. И снова получите ответ I am a local var. Как видите, хотя имена у локальной var1 и глобальной var1 одинаковые, но это разные переменные.

 

Переменные характеризуются временем жизни и областью видимости. Локальные переменные определяются внутри функции путем задания слеша с пробелом перед ними. Время жизни локальной переменной совпадает с временем выполнения процедуры. Область видимости локальной переменной ограничена только процедурой (функцией), в которой она задана. Вне этой процедуры текущие значения локальной переменной недоступны.

При объявлении глобальных переменных слеш не ставится. Время жизни глобальной переменной совпадает с временем открытия чертежа. Областью ее видимости является весь проект.

 

2.   Работа с системными переменными

 

Среда AutoCAD содержит много системных переменных, которые управляют процессом черчения. Текущие значения системных переменных можно читать и изменять. Не путайте понятия переменной и системной переменной. Переменная — это величина, которая создается для использования в процедуре. Системная переменная — это параметр AutoCAD, который служит для настройки режима работы с чертежом. Для изменения текущего значения системной переменной нужно набрать ее имя в командной строке.

 

Пример 1

Системная переменная FILEDIA включает (значение равно 1) и выключает (значение равно 0) вывод на экран диалоговых окон выбора файлов по команде File — Open. Проверьте это. Затем верните старое значение:

 

Command: filedia

Enter new value for FILEDIA <1>: 0

 

Пример 2

При запуске функции COMMAND процедур AutoLISP все сообщения команд AutoCAD отображались в командной строке. Системная переменная CMDECHO определяет, будут ли отображаться в командной строке приглашения и параметры при работе функции COMMAND. По умолчанию режим отображения включен — текущее значение системной переменной равно 1. Если изменить это значение на 0, то режим отображения отключится.

 

Для работы с системными переменными в среде AutoLISP используются операторы SETVAR и GETVAR.

Оператор SETVAR (SET VARiable — установить переменную) изменяет текущее значение системной переменной. Новое значение помещается после имени переменной, заключенной в двойные кавычки: (setvarcmdecho” 0).

Оператор GETVAR (GET VARiable — получить переменную) возвращает значение системной переменной. Его можно присвоить другой переменной или системной переменной. Часто так возвращают системной переменной старое значение, которое изменялось в процессе работы процедуры. Синтаксис операции: (getvarcmdecho”).

 

Задание 4.3

Работа в среде AutoLISP с системными переменными

 

Создайте новый чертеж. Откройте редактор Visul LISP. Откройте новый файл и наберите в нем следующие процедуры:

 

(defun chred (selected_object)

(command “_chprop” selected_object “” “_color” “red” “”)

)

(defun c:chgcolor (/ selected old_cmdecho)             ;описываем две локальные переменные

(setq old_cmdecho (getvarcmdecho”))      ;присваиваем old_cmdecho значение 1

(setvarcmdecho” 0)                                                ;присваиваем cmdecho новое значение 0

(terpri)                                    ;в командной строке выводится начало пустой строки

(setq selected (entsel “Выделите объект для изменения цвета на красный:”))

(chred selected)

(setvar “cmdecho” old_cmdecho))

 

Процедура работает следующим образом.

1.      В функции chgcolor добавляется переменная old_cmdecho.

2.      Этой переменной присваивается текущее значение системной переменной cmdecho, равное 1. Текущее значение считывается оператором getvar.

3.      Системной переменной cmdecho присваивается новое текущее значение 0.

4.      В последней строке восстанавливается старое значение системной переменной cmdecho оператором присвоения setvar.

 

После составления процедуры выполните следующие действия:

1.      Сохраните файл.

2.      Щелкните на кнопке Load Active Edit Window — загрузите процедуру.

3.      Щелкните на кнопке Activate AutoCAD — перейдите в AutoCAD.

4.      Начертите произвольный объект.

5.      Наберите в командной строке chgcolorÃ

6.      В ответ на приглашение выделите объект, нарисованный по п.4.

7.      Проверьте текущее значение системной переменной cmdecho.

3.   Функции AutoLISP

 

Определение функции всегда начинается с оператора DEFUN. При этом можно выделить три типа функций:

1.      Именам функций предшествует префикс С:.Это позволяет использовать имя функции как команду AutoCAD. В выражениях AutoLISP при ссылках имя функции вместе с префиксом заключают в круглые скобки (с:name).

2.      Имена функций создаются без префикса С:. Такой тип функций наиболее удобен при вызове функции по имени другими выражениями AutoLISP. Но в командной строке необходимо заключать имя функции в круглые скобки.

3.      Третий тип функций — S::STARTUP. Функция с таким именем будет автоматически выполнена после инициализации чертежа. Функции сохраняют в файлах acad.lsp и acaddoc.lsp. Эти файлы инициализации, создаваемые пользователем, загружаются автоматически. Файл acad.lsp загружается один раз перед началом сеанса AutoCAD, а файл acaddoc.lsp загружается перед открытием каждого нового чертежа.

 

Задание 4.4

Создание файла инициализации

 

Пусть вы хотите увидеть рамку с приветствием на экране при открытии каждого чертежа. Создадим процедуру и сохраним ее в файле AutoCAD 2007\Support\acaddoc.lsp:

 

(defun s::startup ()

(command “rectang” “_width” “5” “0,0” “50,35”)

(command "_chprop" "_last" "" "_color" “t” "255,0,0" “”)

(command “_text” “10,15” “” “Hello!”)

(command "_chprop" "_last" "" "_color" “t” "255,0,0" “”)

(command "_zoom" "_extents" "")

)

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

В среде AutoLISP можно создавать функции с аргументами. Аргумент передает свое значение функции. Функция использует значение аргумента в процессе отработки операций. Аргументы располагают в круглых скобках до косой черты (слеша). Если у функции нет локальных переменных, то слеш не ставится. Пример объявления функции с одним аргументом приведен в задании 4.3: (defun chred (selected_object)…

Функцию с аргументом можно вызвать и выполнить с помощью оператора вызова функции. В операторе задается имя функции и фактические переменные, которые заменяют в теле функции формальные аргументы. В задании 3.3 формальным аргументом является переменная selected_object. Фактическим параметром, передаваемым функции chred в качестве аргумента является переменная selected. При каждом обращении к функции chred из какой-либо процедуры необходимо задавать значение аргумента. В качестве аргумента можно использовать:

·         переменную, значение которой вычислено в вызывающей процедуре;

·         значение, введенное пользователем;

·         значение, заданное при использовании функции.

 

Вернемся к заданию 4.3 и опишем работу функций.

В первой строке определена функция chred и ее аргумент selected_object.

При вводе в командную строку команды chgcolor начинает выполняться функция c: chgcolor. В предпоследнем операторе функции — (chred selected) — управление передается функции chred с аргументом. Значение переменной selected извлекается из предыдущего этапа как результат операции entsel. Переменная selected — это аргумент, который передается функции chred. Функция подставляет при осуществлении своих действий вместо аргумента selected_object значение переменной selected.

Прорабатывая свой код, функция chred применяет команду chprop для изменения цвета объекта на красный.

 

4.   Операторы условия, циклы и работа со списками

 

Синтаксис условного оператора имеет стандартный вид:

 

(if условное_выражение  Если_True  Если_False)

 

Значение Если_False можно опустить. Тогда интерпретатор исполнит выражение Если_True, когда условное выражение истинно. Если же условное выражение ложно, то управление перейдет к следующему оператору.

 

Задание 4.5

Работа с оператором IF

 

(defun c:compare (/ num)

(setq num (getint “\nВведите число:”))

(if (< num 3)

(princ “\nВведенное число меньше 3”)

(if (= num 3)

(princ “\nВведенное число равно 3”)

(princ “\nВведенное число больше 3”)))

(princ))

 

Префикс \n аналогичен оператору terpri: каждое новое приглашение будет выводиться с новой строки. Выполните действия и оцените результат:

1.      Загрузите процедуру в файл.

2.      Запустите процедуру, набрав в командной строке compareÃ.

3.      Введите число 2.

4.      Нажмите ENTER и введите число 3.

5.      Нажмите ENTER и введите число 7.

 

Операторы цикла обеспечивают выполнение определенных операторов несколько раз подряд. При использовании циклического оператора WHILE количество повторов неопределенно. Цикл выполняется, пока истинно условное выражение. Иначе управление передается следующему оператору:

 

(WHILE  условное_выражение  тело_цикла)

 

Чаще нужно выполнить цикл определенное число раз (итераций). Для этого создается специальная переменная — счетчик. Условием выхода из цикла является заданное число итераций.

Пример

(defun c:cycle  (/ counter)

(setq counter 1)

(while (< counter 6)

(princ “Number ”)

(princ Counter))

(terpri)

(setq counter (+ 1 counter))

))

Счетчиком является переменная counter. В начале процедуры функция cycle присваивает счетчику counter значение, равное 1. Затем оператор while печатает слова Number Counter и увеличивает значение счетчика на единицу. Условием работы оператора while является то, что значение счетчика меньше 6.

В результате программа выдаст следующий список:

Command: cycle

Number 1

Number 2

Number 3

Number 4

Number 5

6

В последней строке напечатано возвращаемое значение функции. Обычно им является значение последнего вычисленного в теле функции оператора. Число 6 — это значение переменной, над которой выполнял действие последний оператор функции.

При зацикливании можно прервать выполнение процедуры, нажав ESC, CTRL+BREAK или выбрав команду в меню Visual LISP: Debug — Abort Evaluation (Отладка — Прервать вычисления).

Если необходимо объединить несколько операторов в один блок, то используется функция PROGN. Все, что включено в конструкцию PROGN, рассматривается интерпретатором как один оператор.

(defun c:compare1 (/ num)

(setq num (getint “\nВведите число”))

(if (< num 3)

(princ “\nВведенное число меньше 3”)

(if (= num 3)

(progn

(princ “\nВведенное число равно 3”)

(terpri)

(princ “\nЭто и есть результат эксперимента”)

)

(princ “\nВведенное число больше 3”)

))

(princ))

 

Списки — это основные структуры данных, используемые в процедурах на языке AutoLISP. В программе AutoCAD данные об объекте формируются в виде списка, который содержит списки меньшего размера.

В AutoLISP список заключается в круглые скобки. Нумерация элементов в списке начинается с нуля. Примером списка является задание координат точки в прямоугольной системе координат X,Y,Z: (1.2 3.4 5.6).

Стандартной операцией во всех языках является извлечение из списка одного или нескольких элементов. Основные функции AutoLISP извлечения из списка приведены в таблице:

 

Функция

Результат

Описание

CAR

1.2

Возвращает первый элемент списка

CDR

(3.4 5.6)

Возвращает все элементы списка, кроме первого

CADR

3.4

Возвращает второй элемент списка

CADDR

5.6

Возвращает третий элемент списка

NTH

 

Возвращает произвольный элемент списка

 

Функции NTH нужно задать два параметра: номер элемента и имя списка. Список создается функцией LIST. Если элементы списка являются константами, а не переменными, то для его создания можно использовать функцию QUOTE. Вместо имени QUOTE часто ставят одинарную кавычку. Функции для работы со списками описаны в разделе AutoLISP Developer’s Guide — Appendixes — Basic Functions — List Manipulation Functions справочной системы AutoCAD.

 

Пример

(defun c:funlist  (/ corner)

(setq corner (list 1.2 3.4 5.6))

(nth 0 corner)

)

При запуске этой процедуры функция возвращает значение нулевого члена списка.

 

5.   Оформление процедуры

 

При создании процедуры особое внимание следует обращать на обработку ошибок и комментарии. Например, в предыдущем задании требовалось выделить текстовый объект. Если пользователь выделил не текст, то должно быть выдано сообщение: «Выделите текст». Чаще всего такие проверки осуществляют с помощью оператора IF. Для выполнения оператора IF требуется проверка логического выражения на истинность. Если пользователь не выделит объект нужного типа, то логическое выражение примет значение nil. В эту часть условного оператора и нужно поместить сообщение об ошибке.

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

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

;;; — три точки с запятой. Такой комментарий выравнивается по левому краю. Он используется в начале процедуры для описания ее назначения и функционирования.

;; — две точки с запятой. Этот комментарий сдвигается в процессе форматирования на уровень следующих скобок. Такой тип комментариев используется для пояснения следующих за ним одной или нескольких строк кода.

; — точка с запятой. Комментарий, помеченный таким символом, сдвигается вправо на 40 символов. Это значение можно изменить в диалоговом окне Format options, открываемом по команде ToolsEnvironment OptionsVisual LISP Format Options. Данный тип комментария обычно используется для текущих пояснений в правой части кода. Записи хорошо выделяются на фоне кода.

;| |; — внутренний комментарий. Его можно поместить внутри любой строки кода. Текст комментария ограничивается точкой с запятой и вертикальной чертой.

;_ — комментарий в конце строки. Используется в конце любой строки. Чаще всего в нем объясняют, какой оператор закрывает данная скобка. Это особенно касается условных операторов, когда закрывающая скобка расположена через несколько строк после открывающей скобки.

 

 

6.   Отладка кода

 

Отладка (debugging) является необходимым этапом создания программы. В процессе отладки нужно найти и устранить ошибки. Visual LISP предоставляет свои средства отладки.

Для начала загрузите функцию, заведомо содержащую ошибку. Введите ее в редактор Visual LISP и загрузите.

 

;;;При попытке выполнения этой функции возникает ошибка, так как функция

;;;strcat предназначена для объединения строк

(defun Error-Prone-Code ()

(strcat “”Эта функция никогда не напечатает число:” 1)

)

 

Выберите команду Debug — Break on Error — тогда редактор автоматически перейдет к строке кода с ошибкой.

Проверим работу отладчика. Введите в окне Console выражение (Error-Prone-Code)Ã Visual LISP возвратит сообщение об ошибке:

; error: bad argument type: stringp 1

Получив сообщение, щелкните на кнопке Last Break (последнее прерывание). Вы перейдете в строку кода, которая содержит ошибку.

 

Задание 4.6

Поиск ошибки

 

В новом чертеже в редакторе Visual LISP введите следующий код:

;;;Функция add-3-numbers выполняется правильно только в том случае,

;;;когда все три ее параметра являются числами

(defun add-3-numbers (num1 num2 num3)

            (+ num1 num2 num3)

)

Загрузите содержимое активного окна.

В окне Console введите (add-3-numbers 1 2 3)Ã Среда вернет 6.

В окне Console введите (add-3-numbers 1 “a” 3)Ã Среда вернет сообщение об ошибке: error: bad argument type: numberp: “a”.

Выберите команду Debug — Break on Error.

Щелкните на кнопке Last Break панели инструментов Debug. Вы автоматически перейдете в строку, где найдена ошибка. Чтобы продолжить работу в режиме Break on Error щелкните на кнопке Reset панели инструментов Debug.

 

Иногда в режиме Last Break выделенной оказывается слишком большая часть кода, что затрудняет поиск ошибки. В этом случае всю программу разделяют на небольшие фрагменты точками прерывания. В этих точках приостанавливается выполнение программы — AutoLISP ожидает дальнейших инструкций от пользователя.

Чтобы установить точку прерывания, установите курсор справа от закрывающей скобки и нажмите клавишу F9. Строка будет отмечена красной меткой. После разметки необходимо повторно загрузить код, чтобы сообщить Visual LISP об их появлении. Код программы будет выполняться до первой точки прерывания.

При разметке программы становятся доступны кнопки панели Debug. Три первые кнопки этой панели предоставляют три разных способа перемещения в пределах кода:

1.      STEP INTO — вход внутрь выражения начиная со скобок самого глубокого уровня вложенности.

2.      STEP OVER — переход к следующей строке кода, не углубляясь во вложенные выражения.

3.      STEP OUT — переход к концу функции, можно без остановки пройти всю функцию.

Чтобы удалить точки прерывания, выберите команду Debug — Breakpoints Window. Активизируется диалоговое окно для просмотра и удаления точек прерывания.

 

7.   Упражнения

 

1.      В задании 4.4 составлен файл инициализации, выводящий на экран приветствие при открытии чертежа. Дополните процедуру операциями, которые удаляют приветствие с экрана.

2.      Системная переменная ISOLINES определяет число изолиний, которые используются для построения объемных тел. Создайте процедуру построения сферы. С помощью оператора SETVAR задайте число линий равным 0 или 64. Сравните вид сферы в режимах 2DWireframe и Realistic.

3.      Наберите в новом файле следующий код:

 

;;; to the console in a more human readable format.

(defun VertList (aList)

;; this will print every item in the list

(princ (chr 40))                       ; an opening parenthesis

(princ (car aList))                   ; the first item in the list

(foreach item  (cdr aList)       ; the rest of the list except the beginning

(terpri)                                    ; place a new line

(princ " ")                                ; print a space

(princ item 1)                          ; and print the item in the list

                                               ; This is bugged because princ has an optional argument,

                                               ; an opened file; however 1 is an integer, not an opened file.

                                               ; See Princ in the AutoLISP Reference.

                                               ; To correct this, the expression should be (princ item)

)

(terpri)

(princ (chr 41))                       ; closing parenthesis

(terpri)                                    ; a new line

T                                             ; returns T

)

Эта процедура создает вертикальный список чисел. Введите в окне Console следующую строку:

(VertList ‘(1 2 3 4 5))

Интерпретатор возвратит Вам сообщение об ошибке. Установите точки прерывания в третью, четвертую и девятую строки кода. С помощью оператора Step Into найдите оператор с ошибкой. Сохраните файл в исправленном виде.

Hosted by uCoz