Введение в Автолисп

Рыжиков Роман Клавдиевич

4. ОРГАНИЗАЦИЯ ПАУЗ И ВЕТВЛЕНИЕ ПРОГРАММ

 

 

4.1. Организация пауз для ввода данных

Автолисп содержит ряд функций, объединенных общей структурой getxxx, вызывающих паузу в работе программ и ожидающих ввода запрашиваемых данных. Эти функции перечислены в табл. З.

Tаблица 3. Функции запроса данных

Имя функции Характер запрашиваемой информации
getint Целое число из командной строки
getreal Вещественное число из командной строки
getstring Строковая константа из командной строки
getpoint Координаты точки из командной строки или прямым указанием точки на экране
getcorner Координаты одного из противолежащих углов окна или секущей рамки из командной строки или прямым указанием на экране
getdist Целое или вещественное число, определяющее необходимое расстояние, из командной строки или прямым указанием отрезка на экране
getangle Величина угла из командной строки или указанием трех точек на экране
getorient To же
getkword Альтернативный выбор по ключевому слову

Функции getint, getreal и getstring требуют ввода в командную строку параметра соответствующего типа.

Функции getangle и getorient требуют ввода величины угла. Разница заключается в том, что getorient запрашивает угол, измеряемый от положительного направления оси X, getangle - от направления некоторой определенной базовой линии. При этом направление отсчета определяется значением системной переменной Автокада ANGDIR.

В примере использованы две из перечисленных функций. Первая запрашивает точку вставки блока, вторая - некоторое расстояние (в данном случае - длину резьбы на теле болта):

(setq pt1 (getpoint “\nУкажите точку вставки:_ “)),

(setq I2 (getdist “\nУкажите длину резьбы:_ “)).

К семейству getxxx относятся еще две функции: getvar и getenv, но они не являются средством общения с пользователем. Первая, уже использованная ранее, служит для извлечения из Автокада числовых, а вторая - строковых системных переменных.

Все перечисленные функции позволяют осуществить ввод данных на любом этапе работы программы, но они не могут быть использованы при выполнении команды Автокада, т.е. не могут быть включены в команду. Например, если определен некоторый набор примитивов ss, выбрана базовая точка набора pt1, а сам набор необходимо перенести в другую точку, указываемую оператором, нельзя использовать конструкцию

(command “move” ss “” pt1

(getpoint “\nPoint of displacement:_ ")

),

поскольку функция getpoint расположена внутри функции command. Автолисп ее не поймет и прекратит выполнение программы.

Для прерывания команды Автокада Автолисп использует описанный ранее внутренний идентификатор pause. Правильным для описываемой ситуации является формат:

(command “move” ss “” pt1 pause).

 

4.2. Условное ветвление программ

Ветвление программ по заданному условию свойственно всем языкам программирования. Например, в Фортране оператор условного перехода может выглядеть подобно следующему:

IF (условие) GO TO метка,

или в Паскале:

if условие then процедура1 else процедура2.

Аналогичные операции могут быть выполнены и в Автолиспе. Для условного ветвления программ Автолисп предлагает две функции: cond (основная) и if.

(cond ( условие1 операция1 ...) ...) . Функция воспринимает любое число списков как аргументы. Просматривая по очереди первые элементы списков, отыскивает первый, отличный от nil и выполняет операцию. Пример использования этой функции представлен в программе plw.lsp, описываемой несколько ниже.

(if условие операция [альтернативная операция] ) . Эта функция оценивает условие, и если оно не nil, выполняет операцию , в противном случае выполняет альтернативную операцию . Если альтернативная операция опущена или условие есть nil, функция возвращает nil.

В тех случаях, когда программируемой операции предшествуют некоторые предварительные выкладки, внутри функции if используется функция progn, позволяющая совершить последовательно несколько операций и подчиняющаяся формату (progn [ выражение ]...) .

 

4.3. Использование ключевых слов

Ключевые слова в Автолиспе обычно используются для указания пути при ветвлении программ или подтверждения сделанного выбора. Осуществляются эти операции функцией getkword, записываемой в формате

(getkword [ запрос ])

и обязательно сопровождаемой функцией initget.

(initget [биты] [строка] ) . Функция устанавливает ключевые слова и режимы, в которых работают функции группы getxxx, кроме getstring и getvar. В практике часто используется конструкция:

(initget 1 “Yes No”).

Режимы работы функций определяются битовыми значениями, которые накладывают определенные ограничения на ввод данных. В частности, использованный в примере бит 1 запрещает пустой ввод, бит 2 - ввод нулевого значения, бит 4 - ввод отрицательных чисел.

Аргумент строка содержит ключевые слова, подчиняющиеся определенным правилам. Каждое ключевое слово должно отделяться от других одним или несколькими пробелами, из доступных символов содержать только буквы, цифры и дефис, при ответах на запрос можно использовать аббревиатуры, если ключевые слова записаны одним из двух следующих способов:

• подобно тому, как это осуществляется при вводе в командную строку опций Автокада, часть ключевого слова записывается прописными буквами, которые и используются в качестве аббревиатуры, а остальная часть - строчными буквами (например: “LType”, “eXit”, “toP”);

• ключевое слово записывается прописными буквами, а сразу следом за ним через запятую записывается аббревиатура (например: “LTYPE,LT” ). Некоторое неудобство этого способа заключается в том, что аббревиатура обязательно должна включать первую букву слова. Поэтому запись “EXIT,X” не будет восприниматься.

Если ключевые слова записаны целиком прописными или строчными буквами, они должны вводиться полностью.

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

(initget (+ 1 2 4))

(setq lenline

(getreal "\nВведите длину отрезка:_”)

).

Битовые значения представлены арифметической функцией (+ 12 4) только с целью наглядности. Обычно битовые значения, если они используются (например, в описываемой в разделе 6.6 системной переменной OSMODE), сразу представляются их суммой. В рассматриваемом случае это должно выглядеть так:

(initget 7).

Более подробно принципы использования функции initget освещены в [1, 3, 4].

Возвращаясь к примеру, описанному в разд. 4.1, организуем запрос, нужно ли перемещать набор в новое положение.

(initget “Yes No”)

(setq x (getkword “\nПepeмecтить набор? (Yes or No): "))

(if (= x “Yes”)

(command “move” ss “” pt1 pause)

)

В этом примере немаловажно следующее обстоятельство. В функции initget опущен аргумент биты , следовательно на ввод не накладываются никакие ограничения. Это дает возможность установить выбор по умолчанию, которое в данном случае представляет собой отказ от перемещения набора. Поэтому пустой ввод, т.е. нажатие клавиши Enter, вызывает именно эту реакцию. Ввод же литер “Y”, “у” или слов “Yes”, “yes” организует базовую точку набора pt1, после чего программа будет ожидать указание нового положения базовой точки.

 

4.4. Вычерчивание болта

Ранее уже говорилось о том, что оформление стандартных элементов чертежей (узлов, деталей и т.п.) в виде блоков приводит к разрастанию графической базы данных до немыслимых размеров. Целесообразнее написать программу, которая обрисовывала бы часто используемые детали в соответствии с заданными параметрами. Рассмотрим структуру такой программы на примере вычерчивания болта (рис. 1).

Основными параметрами болта являются: наружный d и внутренний d вн диаметры резьбы, длина стержня l и длина нарезки l 0 . Для упрощения демонстрационной программы ycтановим высоту головки болта h г равной 0.7d, большую хорду головки в плане равной 2d, глубину нарезки равной 0.87t, где t - шаг резьбы. Эти параметры соответствуют стандарту метрической резьбы. Болт изобразим в упрощенном виде, т.е. без обрисовки фасок на головке и стержне. В качестве точки вставки примем точку пересечения оси болта с линией опорной поверхности головки (точка p5 на рис. 1). Предполагаем, что в чертеже созданы ранее необходимые слои (например, путем загрузки описанных выше стандартных форматов). Обозначение точек на чертеже соответствует идентификаторам, используемым в программе.

Рис. 1. Условное изображение болта. Обозначения точек соответствуют идентификаторам, принятым в программе

;;; ===============================================

(defun C:BOLT ()

;;; Ввод параметров болта

(setq p5 (getpoint “Insertion point:_"))

(setq dia (getdist “\nInput diameter:_”))

(setq l1 (getdist “\nInput length of bolt:_"))

(setq I2 (getdist “\nInput length of screw:_"))

;;; Угловые точки головки болта

(setq p6 (polar p5 (/ pi 2.0) dia))

(setq p7 (polar p6 pi (* dia 0.7)))

(setq p8 (polar p7 (+ pi (/ pi 2.0)) (* 2.0 dia)))

(setq p9 (polar p8 0.0 (* dia 0.7)))

;;; Концевые точки ребер головки

(setq p1 (polar p8 (/ pi 2.0) (* dia 0.5)))

(setq p4 (polar p1 (/ pi 2.0) dia))

;;; Угловые точки стержня болта

(setq p2 (polar p1 0.0 (+ l1 (* dia 0.7))))

(setq p3 (polar p2 (/ pi 2.0) dia))

;;; Точки, ограничивающие длину резьбы:

;;; 1. по внешнему диаметру резьбы

(setq p10 (polar p3 pi l2))

(setq p11 (polar p2 pi l2))

;;; 2. по внутреннему диаметру резьбы

(setq p12 (polar p2 (/ pi 2.0) (* dia 0.08)))

(setq p13 (polar p12 (/ pi 2.0) (* dia 0.84)))

(setq p14 (polar p12 pi l2))

(setq p15 (polar p13 pi l2))

;;; Концевые точки осевой линии

(setq p16 (polar p5 pi dia))

(setq p17 (polar p5 0.0 (+ l1 10.0)))

;;; Сохранение имени рабочего слоя

(setq old_lay (getvar “clayer”))

;;; Вычерчивание болта в нужных слоях

;;; и создание набора примитивов

(command “layer” “set” “contur” “”)

(command “pline” p1 “w” “0.8” “” p2 p3 p4 “”)

(ssget ss1 “L”)

(command “pline” p6 p7 p8 p9 “C”)

(ssget ss2 “L")

(command "layer" "set" "0" "")

(command “line” p10 p11 “”)

(ssget ss3 “L”)

(command “line” p12 p14 “”)

(ssget ss4 “L”)

(command “line” p13 p15 “”)

(ssget ss5 “L”)

(command “layer” “set” “center” “”)

(command “line” p16 p17)

(ssget ss6 “L”)

;;; Поворот и перемещение изображения

(initget “Yes No”)

(setq x (getkword “\nRotate bolt? (Yes or No): “))

(if (= x “Yes”)

    (command “rotate” ss1 ss2 ss3 ss4 ss5 ss6 “” p5 pause)

)

(initget “Yes No”)

(setq x (getkword “\nMove bolt? (Yes or No): “))

    (if (= x “Yes”)

      (command “move” ss1 ss2 ss3 ss4 ss5 ss6 “” p5 pause)

)

;;; Восстановление рабочего слоя

    (command “layer” “set” old_lay “”)

    (command “redraw”)

    (princ)

)

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

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