Книга

Об авторах | Содержание

Предыдущий раздел ! | Следующий раздел !

Глава 12. AutoLISP в среде Visual LISP.

Часть 3.

12.4. Встроенные функции

12.4.6. Функции, работающие со списками и точечными парами

Следующая группа функций - это функции, работающие со списками и точечными парами. Точечная пара - это двухэлементный список вида (а . b), в котором в качестве особого разделителя выступает точка (точка в такой записи отделяется пробелом как от первого, так и от второго элементов). Точечные пары используются для хранения в файлах системы AutoCAD данных о графических примитивах (см. разд. 12.6). Первый элемент точечной пары обычно является целым числом и называется DXF-кодом, а второй - данными этого кода. Основной способ получения точечных пар - функция cons.

Есть отличия в работе некоторых функций со списками и с точечными парами.

Функция list - это основная функция, позволяющая создать список:

(list (<элемент1> [<элемент2> ... [<элементN>] ... ] ] )

В качестве аргументов <элементы>, из которых образуется список, могут выступать любые объекты, которыми оперирует AutoLISP. Самый распространенный список - это список из двух или трех вещественных чисел, представляющий точку.

В качестве элементов списка могут выступать другие списки или точечные пары.

Примеры:

(list 12.12 0.34 5.88) - возвращает (12.12 0.34 5.88);

(list 1 "ad2" (list 0 1 2)) - возвращает (1 "ad2" (0 1 2)) (третьим элементом нового списка является список из чисел 0, 1 и 2).

Следующие функции выполняют основные операции со списками:

  • (append [<список1> [<список2> ... [<списокN>] ... ] ] ) - слияние списков в один;
  • (nth <номер> <список>) - извлечение из списка элемента по порядковому номеру (нумерация элементов списка выполняется слева направо и начинается с нуля);
  • (reverse <список>) - переворот списка;
  • (car <список>) - извлечение первого элемента списка или точечной пары;
  • (cdr <список>) - извлечение из списка подсписка путем удаления первого элемента, если аргумент <список> является простым списком (т. е. не точечной парой), или извлечение второго элемента, если <список> является точечной парой.

Примеры:

(append '(14 16) '(12.12 0.34 5.88)) - возвращает (14 16 12.12 0.34 5.88);

(nth о '(12.12 0.34 5.88)) - возвращает 12.12;

(reverse '(12.12 0.34 5.88)) - возвращает (5.88 0.34 12.12);

(car '(12.12 0.34 5. 88)) - возвращает 12.12;

(car '(62 . 1)) - возвращает 62;

(cdr '(12.12 0.34 5.88)) - возвращает (0.34 5.88);

(cdr ' (62 . 1)) - возвращает 1.

От функции car и cdr путем их повторения в разных комбинациях от двух до четырех раз в языке AutoLISP образованы следующие функции (их двадцать восемь):

  • (сааr <список>) -равносильно (car (car <список>));
  • (cadr <список>) -равносильно (car (cdr <список>));
  • (cdar <список>) -равносильно (cdr (car <список>));
  • (cddr <список>) -равносильно (cdr (cdr <список>));
  • (саааr <список>) - равносильно (car (car (car <список>)))
  • (caadr <список>) - равносильно (car (car (cdr <список>)))
  • (cadar <список>) - равносильно (car (cdr (car <список>)))
  • (caddr <список>) - равносильно (car (cdr (cdr <список>)))
  • (cdaar <список>) - равносильно (cdr (car (car <список>)))
  • (cdadr <список>) -равносильно (cdr (car (cdr <список>)))
  • (cddar <список>) - равносильно (cdr (cdr (car <список>)))
  • (cdddr <список>) -равносильно (cdr (cdr (cdr <список>)))
  • (caaaar <список>) -равносильно (car (car (car (car <список>))));
  • (caaadr <список>) -равносильно (car (car (car (cdr <список>)))).

Аналогичным методом раскрываются оставшиеся функции (caadar, caaddr, cadaar, cadadr, caddar, cadddr, cdaaar, cdaadr, cdadar, cdaddr, cddaar, cdddar, cddadr, cddddr).

Функция cons добавляет к списку первый элемент или создает точечную пару:

(cons <аргумент1> <аргумент2>)

Если <аргумент2> является списком, то функция cons добавляет в него <аргумент1> в качестве нового первого элемента. Если <аргумент2> является атомом (т. е. не списком), то функция cons создает точечную пару типа (<аргумент1> . <аргумент2>).

Примеры:

(cons 67.4 '(10.3 12.9 -3.9)) - возвращает (67.4 10.3 12.9 -3.9);

(cons "Happy" '("New" "Year")) - возвращает ("Happy" "New" "Year");

(cons 2 4) - возвращает (2 . 4);

(cons 8 "0") - возвращает (8 . "0");

(cons 62 l) - возвращает (62 . l).

Функция member проверяет принадлежность элемента списку:

(member <элемент> <список>)

Если функция member обнаруживает <элемент> в аргументе <список>, то возвращает остаток списка, начиная с этого места; если <элемент> в аргументе <список> не обнаруживается, то функция возвращает nil.

Примеры:

(member 1 '(4 50 1 2)) - возвращает (1 2);

(member 4 '(4 50 1 2)) - возвращает (4 50 1 2);

(member 0 '(4 50 1 2)) - возвращает nil.

Функция assoc применяется к списку, в котором элементами являются списки или точечные пары, и выбирает из этих элементов тот, у которого первый элемент имеет заданное значение:

(assoc <код> <список>)

Если в аргументе <список> имеется несколько элементов, удовлетворяющих требуемому условию, то в качестве возвращаемого значения выбирается первый из них. Функция assoc - основной инструмент в операциях выборки из списка с характеристиками примитива AutoCAD того элемента, который содержит точечную пару с нужным DXF-кодом свойства (цвета, типа линии, веса и т. д.).

Примеры:

(assoc 8 '((8 . "Walls") (62 .4) (6 . "ACAD_IS005W100") ) ) - возвращает (8 . "walls");

(assoc 62 '((8 . "Walls") (62 .4) (6 . "ACAD IS005W100") ) ) - возвращает (62 . 4).

Следующие три функции (apply, mapcar, foreach) позволяют выполнять операции сразу над всеми элементами списка.

(apply '<функция> <список>) - применение функции, заданной аргументом <функция> поочередно ко всем элементам списка, заданного аргументом <список>.

Примеры:

(apply '* (list 2 3 5)) - равносильно (* 2 3 5), поэтому возвращает 30;

(apply 'max (list 2 3 5)) - возвращает 5.

Последний пример показывает, что функция apply удобна, когда какую-то операцию нужно выполнить над аргументами, количество которых заранее неизвестно. Поэтому следует сформировать список, к которому затем применить функцию apply с именем нужной функции в качестве первого аргумента. Читателю следует обратить внимание на употребление перед аргументом апострофа.

(mapcar ' <функция> <список1> [<список2> ... [<списокN>] ... ]) - применение функции, заданной аргументом <функция> сначала к первым элементам каждого из списков (<список1>, , <списокN>), затем - ко вторым элементам и т. д.; результаты объединяются в новый список, который является возвращаемым значением.

Пример:

(mapcar '* '(2 3) '(l 5)) возвращает (2 15), т. к. первый элемент результирующего списка вычисляется как (* 2 l), а второй - как (* 3 5).

Функция foreach позволяет организовать циклическое выполнение выражений (их может быть несколько), поочередно подставляя вместо переменной цикла элементы списка:

(foreach <имя> <список> [<выражение1> [<выражение2>... [ <выражениеN> ] ... ] ] )

Функция возвращает значение последнего вычисленного выражения. Если аргументы <выражение1> ... <выражениеN> не заданы, то функция foreach возвращает nil.

Пример:

(setq s1 0 s2 l)

(foreach p '(1 2 3 4 5) (setq s1 (+ s1 p) ) (setq s2 (* s2 p) ) ) - возвращает 120 (результат вычисления s2 - произведения чисел списка); кроме того, в переменной s1 сформируется сумма чисел списка.

Функция eval позволяет сформировать список и затем вычислить его (evaluate) как выражение. В таком списке на первом месте должно стоять имя функции.

Пример:

(setq mylist (list 'max 1.7 9.34 6.7));

(eval mylist) - возвращает 9.34 (вычисляется выражение (max l.7 9.34 6.7)).

Функция quote является обратной по отношению к функции eval и позволяет обрабатывать выражение как список, т. е. не вычисляя его. Сокращенным вариантом имени функции quote является одинарная кавычка.

Примеры:

(quote б 7 8 2 l) - возвращает (67821);

'(16 23 90) - возвращает (16 23 90).

Функция acad_strlsort позволяет отсортировать по возрастанию список, элементами которого являются строки.

Пример:

(acad_strlsort '("Пн" "Вт" "Ср" "Чт" "Пт" "Сб" "Bс"))- возвращает ("Вс" "Вт" "Пн" "Пт" "Сб" "Ср" "Чт").

12.4.7. Функции ввода данных и указания объектов

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

  • (initget [<флаг>] [<строка>]) - задание ключевых слов и ограничений ввода для функций getint, getreal, getdist, getangle, getorient, getpoint, getcorner, getkword (а также для функций entsel, nentsel и nentselp, рассмотренных в разд. 12.4.9);
  • (getkword [запрос]) - ввод ключевого слова;
  • (getint [запрос]) - ввод целого числа в диапазоне от -32768 до +32767;
  • (getreal [запрос]) - ввод вещественного числа;
  • (getdist [<точка1>] [запрос]) - получение расстояния (как вещест-венного числа) с помощью ввода числа (на клавиатуре в текущей форме линейных единиц) или указания двух точек (мышью или в координатах на клавиатуре), если не задан аргумент <точка1>; если задана точка с помощью аргумента <точка1>, то расстояние можно получить с помощью ввода числа (на клавиатуре) или указания одной точки, до которой расстояние будет вычисляться от точки, заданной аргументом <точка1>;
  • (getangle [<точка1>] [запрос]) - получение угла (как вещественного числа в радианах) с помощью ввода числа (на клавиатуре в текущей форме угловых единиц) или указания двух точек (мышью или в координатах на клавиатуре), если не задан аргумент <точка1>; если задан аргумент <точка1>, то угол можно получить с помощью ввода числа (на клавиатуре в радианах) или указания одной точки, до которой расстояние будет вычисляться от точки, заданной аргументом <точка1>; при вводе угла с помощью числа он принимается с учетом значения системных переменных ANGBASE и ANGDIR; возвращаемое значение учитывает значение ANGBASE и игнорирует значение ANGDIR;
  • (getorient [<точка1>] [запрос]) - получение угла как в функции getangle, однако возвращаемое значение не учитывает значений ANGBASE и ANGDIR (т. е. как будто ANGBASE=0, ANGDIR=0);
  • (getpoint [<точка1>] [запрос]) - ввод точки с помощью клавиату-ры или мыши; если задан аргумент <точка1>, то при вводе точки с помощью мыши рисуется резиновая нить, начинающаяся в точке, заданной аргументом <точка1>;
  • (getcorner <точка1> [запрос]) - ввод точки с помощью клавиатуры или мыши; при вводе точки с помощью мыши рисуется резиновая рамка, начинающаяся в точке, заданной аргументом <точка1>;
  • (getstring [<флаг>] [<запрос>]) - ввод строки; если задан аргумент <флаг> и он отличен от nil, то в строке, вводимой пользователем, допускаются пробелы (признаком конца является <Enter>); если аргумент <флаг> отсутствует или задан равным nil, то признаком конца строки является пробел или <Enter>;
  • (getvar <имя>) - чтение текущего значения системной переменной с наименованием, заданным аргументом <имя>;
  • (getenv <имя>) - чтение текущего значения переменной окружения с наименованием, заданным аргументом <имя>;
  • (getcfg <строка>) - извлечение данных приложения из раздела AppData файла acad.cfg; строка, заданная аргументом <строка>, должна иметь вид "АррDаtа/имя_приложения/имя_раздела/ ... /имя_параметра";
  • (getcname <имя>) - получение имени команды в локализованной или английской версии AutoCAD;
  • (getfiled <заголовок> <имя> <расширение> <флаг> - вызов диалогового окна поиска файла; аргумент <заголовок> используется как заголовок диалогового окна; аргумент <имя> - это имя искомого файла или папки, с которой предлагается начать поиск; аргумент <расширение> - расширение искомого файла (<расширение>, равное "", заменяется на "*"); аргумент <флаг> - опции функции (см. ниже).

Вызов функции initget должен предшествовать в программе обращению к функциям getint, getreal, getdist, getangle, getorient, getpoint, getcorner, getkword, entsel, nentsel и nentselp, поскольку устанавливает

в этих функциях ограничения на ввод пользователем данных. В частности, initget может сохранять за пользователем возможность нажатия клавиши <Enter> вместо ввода данных (например, для выбора значения по умолчанию), а может и не сохранять. Аргумент <флаг> функции initget - это битовый флаг, который должен быть целым числом (от 0 до 255), являющимся суммой битов с соответствующими каждому из них весовыми значениями (нумеруются по степеням числа 2). Биты описываются в табл. 12.3. Если бит не установлен, то его значение в битовом флаге считается равным нулю.

Таблица 12.3. Значения битов функции initget

Бит

Назначение

1

Не разрешает пустой ввод (пустой ввод- это нажатие только клавиши <Enter>)

2

Не разрешает ввод нуля

4

Не разрешает ввод отрицательных чисел

8

Разрешает указание точек за пределами лимитов, несмотря на значение системной переменной LIMCHECK

16

Данный бит не задействован

32

Заставляет AutoCAD использовать штриховую линию вместо сплошной для резиновой нити и резиновой рамки; если значение системной переменной POPUPS равно нулю, то AutoCAD игнорирует данный бит

64

Запрещает ввод третьей координаты для точки в функции getdist

128

Разрешает произвольный ввод в качестве ключевого слова; преобладает над другими битами и ключевыми словами; в частности, данный бит позволяет игнорировать значение бита 1



Примеры использования битового флага:

(initget 1) - не разрешен пустой ввод;

(initget 3) - не разрешены пустой ввод и ввод нуля (3=1+2);

(initget 7) - не разрешены пустой ввод, ввод нуля и ввод отрицательных чисел (7=1+2+4);

(initget 6) - разрешен пустой ввод, но не разрешены ввод нуля и ввод отрицательных чисел (6=2+4).

Аргумент <строка> функции initget - это строка, ограниченная двойными кавычками с двух сторон, которая задает ключевые слова, являющиеся допустимыми вариантами ввода. В аргументе <строка> различные варианты ключевых слов разделяются одним или большим количеством пробелов, например: "А Б В Г Д". Если пользователю при выборе ключевого слова разрешаются сокращенные варианты, тогда обязательная часть ключевого слова и аргументе <строка> должна быть указана в верхнем регистре, например: "ПЕРесечение". В этом случае допустимыми вариантами ввода являются "ПЕР", "пер", "ПЕРЕ", "пере", "перес", "ПЕРЕСЕЧЕН", "ПЕРЕСЕЧЕНИЕ" (после трех обязательных букв может идти любое количество необязательных букв, вплоть до набора полного ключевого слова; при вводе букв верхний и нижний регистры равноправны); недопустимыми вариантами будут "П", "ПЕ", "п", "пе".

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

(initget "выход") - здесь допустимыми вариантами ввода будут "х", "хо", "ход" или "выход", "вых", "выхо".

Если ключевое слово в аргументе <строка> указано только в верхнем или только в нижнем регистре, то рядом через запятую можно указать сокращенный вариант: "КРАСНЫЙ, КР" - равносильно записи "красный".

В локализованных версиях системы AutoCAD в аргументе <строка> могут присутствовать варианты ввода для локализованной и английской версий. Тогда в начале должны идти локализованные ключевые слова, а затем их английские аналоги, причем первый английский аналог должен начинаться с символа подчеркивания. Количество локализованных ключевых слов должно равняться количеству английских ключевых слов. Например: "прямой криволинейный _straight curved". В этом случае даже при вводе русского варианта будет возвращаться английское значение ("Straight" или "Curved").

Сама функция initget всегда возвращает nil. Однако за ней (не обязательно в следующей строке) должна идти функция, для которой функция initget установила ограничения ввода. В качестве возвращаемого значения эта функция (например, getreal) выдает допустимое значение, указанное пользователем, а в случае ввода сокращенного варианта ключевого слова - полный вариант ключевого слова.

Листинг 12.9. Пример 1 использования функции getint

(initget 6) (setq numb (getint "Введите номер участка (<1>): "))

В этом примере сначала устанавливаются ограничения на будущий ввод целого числа (не допускаются ноль и отрицательные числа). Допускается пустой ввод. Функция getint выводит на экран запрос "Введите номер участка (<1>) : ". Ее возвращаемым значением будет nil, если пользователь ответит простым нажатием клавиши <Enter>, или введенное пользователем допустимое целое число (например, 17). В случае ввода пользователем недопустимого целого числа (например, 0 или -2) функция getint выведет сообщение об ошибочном значении и будет ожидать допустимого варианта ввода.

В программе, приведенной в листинге 12.9, далее должна быть предусмотрена обработка пустого ввода для того, чтобы в этом случае присвоить переменной numb значение по умолчанию (1):

(if (not numb) (setq numb 1))

Листинг 12.10. Пример 2 использования функции getint

(initget 6 "Левый Правый Нижний Верхний")

(setq numb (getint "Введите номер участка (<1>) или [Левый/Правый/Нижний/ Верхний]: "))

В этом примере устанавливаются ограничения на будущий ввод целого числа (не допускаются ноль и отрицательные числа), однако допускаются пустой ввод и ввод одного из четырех ключевых слов. Далее в программе должен идти анализ значения переменной numb на nil, на положительное целое число и на ключевые слова ("левый", "правый", "нижний", "верхний").

Листинг 12.11. Пример использования функции getkword

(initget 1 "Да Нет") (setq reply (getkword "Продолжить цикл [Да/Нет]: "))

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

Поскольку не все биты функции initget используются со всеми функциями ввода данных, то в табл. 12.4 разбираются варианты применения (в случае возможности использования ставится плюс).

Функция

Бит1

Бит 2

Бит 4

Битв

Бит 32

Бит 64

Бит 128

getint

+

+

+

 

 

 

+

getreal

+

+

+

 

 

 

+

getdist

+

+

+

 

+

+

+

getangle

+

+

 

 

+

 

+

getorient

+

+

 

 

+

 

+

getpoint

+

 

 

+

+

 

+

getcorner

+

 

 

+

+

 

+

getkword

+

 

 

 

 

 

+


Функции entsel, nentsel и nentselp не используют биты функции initget и управляются только ключевыми словами.

Функция getstring не использует ни биты, ни ключевые слова функции initget.

Функции getvar и getenv позволяют прочитать значения, соответственно, системных переменных AutoCAD и переменных окружения.

Примеры:

(getvar "CECOLOR") - возвращает значение системной переменной "CECOLOR";

(getvar "PDMODE") - возвращает значение системной переменной "PDMODE";

(getenv "CONFIG") - возвращает значение переменной окружения "CONFIG".

Функция getfiled позволяет вызвать диалоговое окно выбора файла в удобном виде.

Пример:

(getfiled "Выберите файл данных для расчета"

"с: \\Ritm\\Genhull\\9ll" "dat" l6) - вызывает окно, приведенное на рис. 12.4:

Рис. 12.4. Диалоговое окно, вызываемое функцией getfiled

Второй аргумент функции getfiled, в зависимости от значения четвертого аргумента (<флаг>), может задавать либо имя файла по умолчанию, либо папку, с которой предлагается начать поиск. Битовый флаг, задаваемый аргументом <флаг> получается как сумма тех битов, нумеруемых степенями числа 2, которые будут установлены. Описание битов приведено в табл. 12.5.

Таблица 12.5. Значения битов функции getfiled

Бит

Значение

1

Подсказка имени при создании нового файла (нельзя использовать для выбора существующего файла)

2

Не используется

4

Разрешает вводить имя файла с любым расширением (или без расширения)

8

Если бит 1 не установлен, то система AutoCAD выполняет поиск файла, имя которого задано в аргументе <имя> по списку путей, заданных в настройке, причем getfiled возвращает имя файла без пути; в противном случае возвращается полное имя файла (с путем)

16

Аргумент <имя> трактуется как имя папки, в которой нужно искать файл; при этом в поле Имя файла: (File name:) ничего не вписывается по умолчанию (см. рис. 12.4); аналогичный эффект достигается и в том случае, если аргумент <имя> заканчивается обратной косой чертой

32

Если установлен бит 1, то не будет выводиться предупреждающее сообщение при записи поверх существующего файла

64

Не передает файл, если в качестве имени задан URL-адрес

128

Не допускается использование URL-адресов


С функциями getvar и getenv тесно связаны функции, выполняющие обратные операции:

  • (setvar <имя> <значение>) - установка значения системной переменной с наименованием, заданным аргументом <имя>;
  • (setenv <имя> <значение>) - установка значения переменной окружения с наименованием, заданным аргументом <имя>.

В обеих функциях аргументы <имя> и <значение> должны быть текстовыми строками.

Функция setcfg является обратной по отношению к функции getcfg:

(setcfg <имя> <значение>) - запись данных приложения в раздел AppData файла acad.cfg; аргумент <имя> должен иметь вил "AppData/ имя_приложения/имя_раздела/ ... /имя_параметра" (до 496 символов длиной); возвращаемое значение функции setcfg - аргумент <значение> или nil (в случае ошибки).

12.4.8. Функции доступа к файлам

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

  • (findfile <файл>) - поиск файла по имени (краткому или полному) или поиск папки по полному имени; если аргумент не содержит полного пути, то поиск выполняется по стандартным путям поиска файлов для системы AutoCAD; возвращается полное имя файла (папки), если он найден, или nil в противном случае;
  • (open <файл> <режим>) - открытие файла с именем, заданным аргументом <файл>; аргумент <режим> -------трока из одного символа, определяющего режим, в котором открывается файл ("w" или "W" - запись, "а" или "А" - дополнение, "г" или "R" - чтение); в предыдущих версиях AutoLISP не допускалось указание режима в верхнем регистре; если аргумент <файл> указывает на несуществующий файл в режимах "w", "W", "а" и "А", то он создается; возвращаемое значение - дескриптор файла (при успешном открытии) или nil (при неудаче);
  • (close <дескриптор>) - закрытие файла; единственным аргументом является <дескриптор> - переменная, создаваемая функцией open и управляющая процессами записи и чтения: функция close возвращает nil, если указан действительный дескриптор, или сообщение об ошибке;
  • (read-line [<дескриптор>]) - чтение строки из файла с заданным де-скриптором; если аргумент <дескриптор> опущен, то выполняется чтение строки с клавиатуры (строка должна закончиться нажатием клавиши <Enter>);
  • (write-line <строка> [<дескриптор>] ) - запись строки, заданной ар-гументом <строка> в файл с заданным дескриптором; если аргумент <дескриптор> опущен или равен nil, то система AutoCAD выводит строку на экран; при записи строка, заданная аргументом <строка>, заносится в файл (или на экран) без ограничивающих ее двойных кавычек;
  • (princ [<аргумент> [<дескриптор>]]) - запись аргумента, который может быть любым выражением AutoLISP (а также числом, списком, строкой, именем примитива и т. д.), в файл с заданным дескриптором: если аргумент <дескриптор> опущен или равен nil, то <аргумент> выводится на экран; если <аргумент> - строка, то при записи она заносится в файл (или на экран) без ограничивающих ее двойных кавычек; если опущены оба аргумента, то функция осуществляет так называемый тихий выход, т. е. не возвращает никакого значения, в том числе nil;
  • (prinl<аргумент> [<дескриптор>] ]) - функция аналогична princ, но если <аргумент> - строка, то при записи она заносится в файл (или на экран) с ограничивающими двойными кавычками; специальные символы (обратная косая черта, кавычки, конец строки и т. п.) предваряются обратной косой чертой; если опущены оба аргумента, то функция prinl тоже осуществляет тихий выход;
  • (print [<аргумент> [<дескриптор>]]) - функция аналогична prini, но при выводе добавляет перед аргументом символ конца строки предыдущей записи, а после аргумента - пробел; тоже может осуществлять тихий выход;
  • (read-char [<дескриптор>]) - чтение символа из файла; если аргумент не задан, то чтение символа из буфера клавиатуры; возвращает код прочитанного символа (аналогично функции ascii); нажатие на клавишу <Enter> возвращает код 10;
  • (write-char <код> [<дескриптор>]) - запись символа с заданным кодом в файл; если аргумент не задан, то вывод символа на экран; возвращает код символа; невозможно с помощью данной функции записать символ с кодом 0;
  • (prompt <сообщение>) - вывод сообщения на экран (если используется установка системы AutoCAD на двухэкранный вычислительный комплекс, то на оба экрана; чтобы избежать этого, можно пользоваться для вывода сообщении функцией princ).

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

Листинг 12.12. Пример использования функций работы с файлами

; Операции записи

(setq ff (open "с:\\test.txt" "w"))

(write-line "Первая строка" ff)

(write-char 65 ff) (write-char 67 ff)

(write-line "Вторая строка" ff)

(close ff)

; Операции чтения

(setq ff (open "c:\\test.txt" "r"))

(setq s1 (read-char ff))

(setq s2 (read-char ff))

(setq strl (read-line ff))

(setq str2 (read-line ff))

(setq str3 (read-line ff))

(close ff)

(setq ff nil)

Первое выражение - (setq ff (open "c: \\test.txt" "w")) - создает переменную ff, в которую заносится дескриптор файла c:\test.txt, открываемого для записи (в первом аргументе функции open обратная косая черта удваивается). Затем выражение (write-line "первая строка" ff) заносит в открытый файл первую запись (текст "Первая строка" из 13 символов) и символы с кодами 13 и 10, которые в файлах последовательного доступа разделяют записи.

Замечание

В операционной системе UNIX признаком конца записи является один символ с кодом 10.

После этого указатель файла показывает на начало второй записи, куда поочередно - с помощью двукратного применения функции write-char - заносятся символы с кодами 65 (буква "А") и 67 ("С"). Затем в продолжение второй записи файла с помощью функции write-line заносится текст "вторая строка" (13 символов) и добавляются символы с кодами 13 и 10, означающие конец второй записи файла. Вслед за этим файл с дескриптором ff закрывается функцией close.

Вторая часть листинга начинается функцией открытия того же файла, но уже в режиме чтения. Затем с помощью двукратного применения функций read-char читаются два первых символа первой записи, которые запоминаются в переменных s1 и s2. После этого в переменную strl читается остаток первой записи. Далее в переменную str2 читается вторая запись файла. Третья операция чтения с помощью функции read-line приносит nil, поскольку в файле c:\test.txt третьей записи нет. По окончании выполнения рассмотренной программы переменная ff очищается (в ней хранился дескриптор файла). Другие переменные получат такие значения:

s1 = 207 (код символа "П");

s2 = 229 (код символа "е");

strl = "рвая строка";

str2 =: "АСВторая строка";

str3 = nil.

Функции princ, prini, print и prompt чаще всего используются для вывода сообщений в командную строку системы AutoCAD, причем prini и print выводят сообщения в кавычках (другие особенности описаны выше). Вместо функции write-line для записи в файл можно пользоваться функцией princ, но заносить признак конца записи, который выглядит как "\n", пользователь должен сам. Например:

(princ "Первая запись\n" ff)

12.4.9. Функции доступа к примитивам

Рисунок в системе AutoCAD имеет организацию, аналогичную организации базы данных, в которой элементы (графические примитивы и неграфические объекты) имеют списковую структуру. Каждый примитив имеет свой тип. Перечислим все эти типы примитивов в алфавитном порядке: 3DFACE, 3DSOLID, ACAD_PROXY_ENTITY, ARC, ARCALIGNEDTEXT, ATTDEF, ATTRIB, BODY, CIRCLE, DIMENSION, ELLIPSE, HATCH, IMAGE, INSERT, LEADER, LINE, LWPOLYLINE, MLINE, MTEXT, OLEFRAME, OLE2FRAME, POINT, POLYLINE, RAY, REGION, RTEXT, SEQEND, SHAPE, SOLID, SPLINE, TEXT, TOLERANCE, TRACE, VERTEX, VIEWPORT, WIPEOUT, XLINE. Как правило, наименование типа совпадает с английским именем команды системы AutoCAD, которая создает графический объект. Поэтому полезно познакомиться с приложением 1, в табл. П 1.2 которого перечисляются английские наименования команд и соответствующие им русские наименования, а также с командами меню Express {приложение 5).

Функции, рассматриваемые в данном разделе, работают с примитивами рисунка, обращаясь непосредственно к их внутренней структуре. AutoLISP имеет средства выбора графических объектов, как по их порядковому номеру, так и по определенным признакам (цвету, слою и т. п.).

Функция entlast извлекает последний неудаленный основной примитив рисунка:

(entlast)

Функция возвращает nil, если в рисунке нет неудаленных примитивов (например, когда вы только что создали новый рисунок); иначе возвращается имя последнего основного примитива в следующем виде:

<Имя объекта: 14а4158>

(< Entity name: 14а4158>)

Полученное имя следует сохранить в переменной, например:

(setq eela (entlast))

Функция entnext позволяет перейти в рисунке к следующему примитиву (подпримитиву):

(entnext [<примитив>])

В качестве единственного аргумента функции entnext может выступать ранее полученное имя примитива текущего рисунка. Если функция вызывается без аргумента, то она возвращает имя первого неудаленного примитива в базе рисунка. При наличии аргумента функция возвращает имя следующего примитива, либо nil, если база графических объектов рисунка исчерпана.

Пример:

(setq el (entnext)) - возвращает имя первого неудаленного примитива;

(setq e2 (entnext е2)) - возвращает имя примитива, следующего за e1;

(setq еЗ (entnext еЗ)) - возвращает имя примитива, следующего за e2.

Функция entlast возвращает имя последнего основного примитива. Это означает, что если последним созданным графическим объектом рисунка является сложный объект (например, полилиния типа POLYLINE), то вслед за ним в базе рисунка следуют подпримитивы, т. е. вершины (имя примитива - VERTEX), а завершается перечисление подпримитивов полилинии примитивом SEQEND.

Пример (в предположении, что объект типа POLYLINE является последним основным примитивом):

(setq eela (entlast)) - возвращает имя основного примитива последней полилинии;

(setq v1 (entnext eela)) - возвращает имя примитива, являющегося первой вершиной полилинии;

(setq v2 (entnext v1)) - возвращает имя примитива, являющегося второй вершиной полилинии.

Замечание

В легкой полилинии (примитиве типа LWPOLYLINE) нет подпримитивов и информация обо всех вершинах может быть извлечена из основного примитива.

Функция entsel предлагает пользователю указать один объект, выдавая соответствующий запрос:

(entsel [запрос] )

Здесь аргумент <запрос> - любая строка текста. Функция возвращает список, состоящий из двух элементов: имени выбранного примитива и точки, которой пользователь указал объект (такая точка, как правило, оказывается вне самого примитива, поскольку точность указания мышью зависит от величины прицела). Можно указать объект вводом с клавиатуры ключевого слова Последний (Last) - тогда в возвращаемом списке координаты точки будут нулевыми.

Пример:

(setq esl (entsel "Выберите объект: ")) - возвращает (<Имя объекта: 14а9960> (301.791 138.438 0.0)).

Имя указанного пользователем объекта может быть извлечено из такого списка, например, с помощью функции car.

Функция entdel позволяет удалять неудаленные основные примитивы и восстанавливать примитивы, ранее удаленные в данном сеансе редактирования:

(entdel <примитив>)

Функция возвращает имя удаляемого (восстанавливаемого) примитива. Следует иметь в виду, что при операции сохранения рисунка все примитивы, помеченные как удаленные, из рисунка стираются и уже больше не могут быть восстановлены.

Функция entget является основным инструментом извлечения информации о примитиве, т. к. получает список с его характеристиками:

(entget <примитив> [<приложения>])

Здесь аргумент <примитив> - это имя примитива для получения его данных, аргумент <приложения> - это список с именами приложений, с помощью которых к примитиву привязаны расширенные данные (о расширенных данных см. разд. 12.4.11).

Предположим, в рисунке первым объектом является отрезок (тип примитива - LINE). Тогда выражение (setq le (entget (entnext) ) ) должно вернуть примерно такой список:

((-1 . <Имя объекта: 14а4158>) (0 . "LINE") (330 . <Имя объекта: 14a40f8>) (5 . "2В") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbLine") (10 201.536 140.622 0.0) (11 285.148 96.5053 0.0) (210 0.0 0.0 1.0))

В этом списке элементами являются точечные пары и списки, причем и в тех, и в других первыми элементами- выступают целые числа, называемые DXF-кодами (см. также разд. 12.4.6). Под соответствующим кодом в точечных парах и списках находятся данные определенного типа: код -1 указывает имя примитива (<имя объекта: l4a4l58>), код 0 - тип примитива ("LINE"), код 5 - метку (внутренний номер примитива в рисунке), код 410 - имя вкладки пространства модели или листа, код 8 - имя слоя ("0"), код 10 - координаты начальной точки (201.536 140.622 0.0), код 11 - координаты конечной точки (285.148 96.5053 0.0), код 210- направление вектора нормали к плоскости, в которой описан примитив. Остальные коды, не имеющие принципиального значения, здесь не рассматриваются. С помощью функции assoc можно из списка с характеристиками объекта извлечь нужную точечную пару, а затем, применив функцию cdr, получить данные необходимого DXF-кода.

Продолжим пример с отрезком:

(cdr (assoc о le)) - возвращает "LINE" (тип примитива);

(cdr (assoc 8 le)) - возвращает "0" (имя слоя);

(cdr (assoc 10 le)) - возвращает (201.536 140.622 0.0);

(cdr (assoc 11 le)) - возвращает (285.148 96.5053 0.0).

Кроме того, по коду 62 можно было бы извлечь номер цвета примитива, по коду 6 - имя типа линии, по коду 48 - собственный масштаб типа линии, по коду 311 - вес линии (умноженный на 100). В рассмотренном выше списке le точечных пар с такими DXF-кодами нет, поэтому для них действуют значения по умолчанию: ПОСЛОЮ (BYLAYER) или 1.

Рассмотрим, какой примерный список можно было бы получить для окружности (объекта типа CIRCLE):

((-1 . <Имя объекта: 14а4160>) (0 . "CIRCLE") (330 . <Имя объекта: 14a40f8>) (5 . "2С") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbCircle") (10 387.691 142.198 0.0) (40 . 27.8941) (210 0.0 0.0 1.0))

Для окружности DXF-коды -l, 0, 410, 8, 210 имеют тот же смысл, что и для всех примитивов (в том числе и для примитива типа "LINE"). Под кодом 40 находится радиус окружности, а точечная пара с DXF-кодом 10 хранит в себе данные о центре.

Поэтому для рассматриваемой окружности:

(cdr (assoc 40 le)) - возвращает 27.8941 (радиус);

(cdr (assoc 10 le) ) - возвращает (387.691 142.198 0.0).

Сравнивая справочную информацию, выдаваемую командой СПИСОК (LIST), и список, получаемый с помощью функции entget, можно получить геометрический смысл DXF-кодов для примитивов других типов.

Если построить в программе список, описывающий примитив (кроме точечной пары с флагом -1), то можно создать в рисунке такой примитив с помощью следующих функций:

  • (entmake <список>) - создает новый примитив по списку, структура которого аналогична структуре списка, возвращаемого функцией entget; функция entmake не может создать примитив типа VIEWPORT; возвращаемое значение - аргумент <список> или nil, если создание объекта невозможно;
  • (entmakex <список>) - создает новый примитив или неграфический объект по списку, аналогично функции entmake; возвращаемое значение - имя нового примитива или nil, если создание объекта невозможно.

Пример:

(entmake '((0 . "CIRCLE") (10 500.0 0.0 0.0) (40 . 50.0)))

создает новый примитив - окружность с центром в точке (500 0 0) и радиусом 50; остальные свойства (слой, цвет и т. д.), данные о которых отсутствуют в списке, берутся по умолчанию.

Функция entmod похожа на функцию entmake, но получает в качестве аргумента список, который содержит точечную пару с DXF-кодом -1 (т. е. имя существующего в рисунке примитива) и модифицирует примитив в соответствии с новым списком (в списке могут изменяться любые данные, кроме имени примитива, типа примитива и метки):

(entmake <список>)

Функция entmod изменяет примитив в базе рисунка и возвращает аргумент <список> при успешном завершении или nil - при невозможности выполнить изменение. Для перерисовки примитива на экране следует воспользоваться функцией entupd:

(entupd <примитив>)

Здесь аргумент <примитив> - это имя примитива в том виде, в котором оно выводится, например, функцией entlast.

Другие функции доступа к примитивам:

  • (handent <метка>) - возвращает имя примитива или неграфического объекта по его метке; аргумент <метка> - это текстовая строка с шестна-дцатеричной меткой в том виде, в каком она возвращается функцией entget;
  • (nentsel [запрос] ) - запрашивает объект и для простого примитива возвращает такой же список из имени примитива и точки указания, как и функция entsel; однако если указанный пользователем примитив является трехмерной полилинией (POLYLINE), то первым элементом возвращаемого списка будет имя подпримитива начальной вершины (VERTEX) участка, на котором указывалась полилиния; если указанный пользователем объект является вхождением блока (INSERT), то возвращается список из двух или четырех элементов (см. ниже); если аргумент оапроо не задан, то в качестве подсказки выводится запрос: Выберите объект: (Select object:)
  • (nentselp [запрос] [<точка>]) - аналогична функции nentsel, но ес-ли указанным примитивом является вхождение блока (INSERT), то возвращает список, в котором третьим элементом является матрица преобразования размером не 4х3, а 4х4 (см. ниже); если задан аргумент <точка>, то запрос не выдается и аргумент выступает в качестве точки указания.

Функция nentsel работает с блоками (точнее, с примитивами типа INSERT) следующим образом. В случае, если пользователь указал атрибут блока, то функция возвращает список из двух элементов: первым является имя объекта-атрибута, а вторым - точка указания атрибута. В случае, если пользователь указал не атрибут, а объект, принадлежащий вхождению блока, то возвращается список из четырех элементов: первым является имя примитива, с помощью которого был указан блок, вторым - точка указания, третьим - матрица размером 4х3 для преобразования точек из системы координат объекта (СКО) в МСК, четвертым - список с именем блока, содержащим указанный примитив (если примитив входит в блок, который вложен в другой блок. то список содержит все имена вкладываемых блоков, начиная от самого внутреннего и кончая самым внешним).

Матрица размером 4х 3, которая выдается в качестве третьего элемента возвращаемого функцией nentsel значения, имеет вид: ((m00 m01 m02) (m10 m11 m12) (m20 m21 m22) (m30 m31 m32)). Тогда преобразование точек из СКО в МСК идет по системе уравнений:

X' = Х*m00 + Y*m10 + Z*m20 + m30

Y' = Х*m01 + Y*m11 + Z*m21 + m31

Z' = X*m02 + Y*m12 + Z*m22 + m32

Здесь (X Y Z) - координаты точки до преобразования, (X' Y' Z') - координаты точки после преобразования.

Функция nentselp работает аналогично функции nentsel, но в случае, если пользователь указал объект, принадлежащий вхождению блока, то тоже возвращается список из четырех элементов, но третьим элементом является матрица размером 4х4, которая служит для преобразования точек из системы координат объекта (СКО) в МСК. Матрица имеет вид: ((n00 n01 n02 n03) (n10 n11 n12 n13) (n20 n21 n22 n23) (0.0 0.0 0.0 1.0)). Преобразование точек из СКО в МСК идет по такой системе уравнений:

X' = Х*n00 + Y*n01 + Z*n02 + n03

Y' = X*n10 + Y*n11 + Z*n12 + n13

Z' = X*n20 + Y*n21 + Z*n22 + n33

Смысл списков (X Y Z) и (X' Y' Z') тот же, что и для функции nentsel.

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

Замечание

При необходимости сохранять наборы примитивов в рисунке следует оформлять их в виде групп с помощью команды ГРУППА (GROUP). Группы относятся к неграфическим объектам, существующим внутри рисунка.

Функция ssget формирует набор по запросу или признаку:

(ssget [<метод>] [<точка1> [<точка2>]] [<список>] [<фильтр>])

Аргумент <метод> - это текстовая строка, принимающая одно из следующих значений (в локализованной версии системы AutoCAD все перечисляемые строки должны спереди дополняться символом "_"), характеризующих метод выбора примитивов:

  • "С" - выбор секущей рамкой;
  • "СР" - выбор секущим многоугольником;
  • "F" - выбор секущей линией;
  • "I" - текущий выбор с помощью ручек;
  • "L" - выбор последнего видимого примитива;
  • "Р" - последний сформированный ранее набор;
  • "W" - выбор рамкой;
  • "WP" - выбор многоугольником;
  • "X" - вся база примитивов рисунка, включая объекты на замороженных слоях и вне видимой части экрана, с учетом аргумента <фильтр> (в этом случае аргумент <фильтр> не должен быть опущен);
  • "А" - вся база примитивов рисунка, включая объекты на замороженных слоях и вне видимой части экрана;
  • ":Е" - все примитивы, попадающие в прицел устройства указания;
  • ":N" - выбор основных примитивов с помощью подпримитивов (вершин полилинии или сети, компонент блока); используется только при графическом варианте выбора и только для указания рамкой, секущей рамкой и точкой; может привести к повторяемости примитивов в наборе, поскольку, например, можно отметить одну и ту же полилинию с помощью любой из ее вершин (слл также функцию ssnamex);
  • ":S" - допускает выбор только одного объекта.

Аргумент <точка1> при отсутствии аргумента <точка2> определяет дополнительное условие для включения в набор: включаемый примитив должен проходить через точку, заданную аргументом <точка1>. Если заданы оба аргумента <точка1> и <точка2>, то заданные ими точки являются углами простой или секущей рамки (когда в качестве метода выбора применяются рамки, т. е. "W" или "С").

Аргумент <список> представляет собой список, элементами которого являются точки, используемые в методах "F", "WP", "СР".

Аргумент <фильтр> - это список со структурой, аналогичной структуре списка, возвращаемого функцией entget, что позволяет оставить только те примитивы, которые удовлетворяют дополнительным признакам (например, определенному цвету, слою, весу и т. д.).

Возвращаемое значение функции ssget - имя созданного набора (или nil, если создать набор невозможно).

Примеры:

(ssget) - выдает стандартный запрос:

Выберите объекты:

(Select objects:)

и далее создает набор в соответствии с дальнейшими указаниями пользователя;

(ssget '(15.78 320.1)) - создает набор из примитивов, проходящих через точку (15.78 320.1);

(ssget "_с" '(1.57 -40.4) '(15.78 320.1)) - создает набор из примитивов, выбираемых секущей рамкой с углами в точках (1.57 -40.4) и (15.78 320.1);

(ssget "_x" '((0 . "POLYLINE") (8 . "WALLS"))) - создает набор из всех примитивов рисунка, являющихся полилиниями типа POLYLINE и лежащими на слое WALLS;

(ssget " А") - создает набор из всех примитивов рисунка, аналогично методу "_Х" с пустым фильтром, т. е. (ssget "_Х" '()) или (ssget "_X" nil).

В рисунке одновременно может быть открыто не более 128 наборов выбора. При достижении такого предела функция ssget отказывается создавать следующие наборы и возвращает nil. Чтобы удалить ненужные наборы, следует присвоить значение nil переменным, хранящим имена этих наборов.

Замечание

В предыдущих версиях системы AutoCAD количество наборов, которые могут быть одновременно открыты, было еще меньше (например, в 10-й версии оно равнялось всего шести).

Для манипуляций с наборами в языке AutoLISP предусмотрены следующие функции:

  • (ssadd [<примитив> [<набор>] ]) - добавление примитива в набор; если аргумент <набор> опущен, а аргумент <примитив> задан, то создается новый набор из одного примитива; если оба аргумента опущены, то создается новый пустой набор (но его значение не равно nil); возвращается имя набора;
  • (ssdei <примитив> <набор>) - удаление примитива из набора, заданных соответствующими аргументами <примитив> и <набор>; возвращается имя набора, если операция удаления выполнена, или nil, если примитив не содержится в наборе и удалить его нельзя;
  • (sslength <набор>) - возвращает количество примитивов в наборе, заданном аргументом <набор>;
  • (ssmemb <примитив> <набор>) - проверка вхождения примитива в набор, заданных соответствующими аргументами <примитив> и <набор>; возвращается имя примитива (т. е. значение аргумента <примитив>), если он входит в рассматриваемый набор, или nil - если не входит;
  • (ssname <набор> <номер>) - извлечение примитива из набора по порядковому номеру, заданных соответствующими аргументами <набор> и <номер>; аргумент <номер> должен быть либо целым числом от 0 до 32 767, либо целым числом в вещественной форме больше 32767.0; нумерация примитивов в наборе начинается с нуля; возвращается имя примитива или nil;
  • (ssnamex <набор> [<номер>]) - извлечение примитива из набора по порядковому номеру (заданных соответствующими аргументами <набор> и <номер>), но при этом выдается дополнительная информация о методах формирования набора (см. ниже); если аргумент <номер> опущен, то выводится информация обо всех примитивах набора;
  • (sssetfirst <набор1> [<набор2>]) - включает ручки у примитивов, входящих в наборы, заданные аргументами <набор1> и <набор2>, но еще и подсвечивает пунктиром примитивы из набора2 (что означает выбор их для следующей операции редактирования);
  • (ssgetfirst) - возвращает список с именами двух наборов, аналогичных по назначению аргументам <набор1> и <набор2> функции sssetfirst (у примитивов набора! включены только ручки, у примитивов набора2 включены ручки и подсвечивание).

Функция ssnamex возвращает список, в котором элементами являются описания способа выбора примитивов, попавших в набор. Если аргумент <номер> не задан, то длина возвращаемого списка равна количеству элементов, определяемых аргументом <набор>. Если аргумент <номер> задан и задан корректно, то возвращаемым значением будет список из одного элемента - описания способа выбора примитива с порядковым номером, равным значению аргумента <номер>. Если же аргумент <номер> задан неправильно, то функция ssnamex вернет nil.

Описание способа выбора примитива - это список из трех элементов: (<метод> <примитив> <данные>). Параметр <метод> - целое число, которое соответствует методу выбора функции ssget и может принимать такие значения:

  • 0 - неинтерактивный выбор ("L", "А", "X" и т. п.);
  • 1 - выбор указанием точки;
  • 2 - "W" или "WP";
  • 3 - "С" или "СР";
  • 4 - "F".

Если на месте параметра <метод> стоит отрицательное число, то оно определяет многоугольник выбора (см. описание многоугольника ниже).

Параметр <примитив> описания способа выбора примитива является его именем в том виде, в котором оно выводится функцией entiast. Параметр <данные> может быть либо только числом 0, либо числом 0 и списком, уточняющим выбор, либо числом 0 и номером многоугольника. В уточняющем списке может быть точка, с помощью которой выбран объект. Если использован номер многоугольника (а он должен быть отрицательным: -1 , -2 и т. п.), то далее будет следовать описание многоугольника с соответствующим номером.

Описание многоугольника- это список такого вида: (<номер_многоугольника> <точка1> ... <точкаN>). Нумерация многоугольников начинается с -1 и наращивается путем добавления -1 к очередному номеру.

Описание точки (<точка1> и т. п.) - это список из трех (или двух) элементов: (<код> <база> [<вектор>] ). Описание точки зависит от вида, на котором она выбиралась, и фактически представляет собой описание прямой, луча или отрезка. Параметр <код> является кодом описания точки (0 - прямая, 1 - луч, 2 - отрезок), параметр <база> представляет собой начальную точку описания, а необязательный параметр <вектор> - это либо направление, в котором продолжается бесконечная линия (прямая или луч), либо смещение в сторону, характерное для отрезка.

Пример:

Если в набор nab5 включен один объект, который был указан точкой (7.51 16.02) на обычном виде сверху в МСК, то выражение

(ssnamex nab5 0) возвращает примерно следующее: ((1 <имя объекта: 14аа560> 0 (0 (7.51 16.02 0.0)))).

В этом примере возвращенный функцией ssnamex список состоит из одного элемента (списка), в котором присутствуют следующие составные части:

  • <метод> - равен 1 (соответствует выбору указанием точки);
  • <примитив> - <Имя объекта: 14аа560>;
  • <данные> - 0 (0 (7.51 16.02 0.0)), что соответствует точке (7.51 16.02 0.0), примененной для выбора примитива.

Другие примеры значений, возвращаемых функцией ssnamex:

((0 <Имя объекта: 14ае578> 0)) - один примитив, выбранный неин-терактивным методом (например, "L");

((3 <Имя объекта: 14ае568> О -1) (3 <Имя объекта: 14ае578> 0 -1) (-1 (0 (-147.787 129.133 0.0)) (0 (-64.2728 129.133 0.0)) (0 (- 64.2728 22.3376 0.0)) (0 (-147.787 22.3376 0.0)))) - два примитива, выбранных секущим прямоугольником с номером -1 (для прямоугольника заданы четыре точки);

((1 <Имя объекта: 14ае560> 0 (0 (74.2672 64.8218 0.0))) (2 <Имя объекта: 14ае570> 0 -1) (2 <Имя объекта: 14ае568> 0 -1) (-1 (0 (-177.446 158.755 0.0)) (0 (40.3151 158.755 0.0)) (0 (40.3151 83.1407 0.0)) (0 (-177.446 83.1407 0.0)))) - три примитива, первый из которых выбран указанием с помощью точки (74.2672 64.8218 0.0), а второй и третий выбраны рамкой, которая фигурирует как многоугольник с номером -1.

В этих примерах параметр <вектор> описания точек нигде не использован, т. е. объекты выбирались на виде сверху в МСК.

Наборы - удобный инструмент для выбора нужных примитивов рисунка с заданными свойствами. После формирования набора затем из него с помощью функции ssname (или ssnamex) извлекаются нужные объекты, с которыми далее выполняются необходимые операции (например: удаление, модификация и т. д.).

12.4.10. Функции доступа к табличным данным и неграфическим объектам

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

Для доступа к табличным объектам в языке AutoLISP имеются такие функции:

  • (tbinext <таблица> [<признак>]) - чтение характеристик очередного объекта из таблицы; допустимые значения параметра <таблица> приведены ниже; если параметр <признак> задан и отличен от nil, то возвращаются данные первого элемента таблицы (иначе возвращаются данные объекта, следующего за тем, который был прочитан в предыдущем обращении к функции tbinext с той же таблицей); если требуемого объекта нет или таблица пуста, то возвращается nil;
  • (tbiobjname <таблица> <заголовок>) - определение объекта таблицы по его заголовку (имени блока, слоя и т. п.); возвращается имя объекта (аналогично имени примитива) в базе рисунка (если объект не найден, то возвращается nil);
  • (tbisearch <таблица> <заголовок> [<следующий>]) - получение списка с характеристиками объекта таблицы по его заголовку; возвращается список, соответствующий найденному объекту (или nil, если объект не обнаружен); если параметр <следующий> задан и не равен nil, то указатель функции tbinext устанавливается на имя элемента <заголовок> (следующее обращение к функции tbinext вернет данные об объекте, расположенном в таблице после объекта, использованного в качестве аргумента в функции tbisearch).

В качестве допустимых значений параметра <таблица> во всех трех функциях могут фигурировать только следующие текстовые строки:

  • "BLOCK" - таблица описаний блоков;
  • "LAYER" - таблица слоев;
  • "LTYPE" - таблица типов линий;
  • "STYLE" - таблица текстовых стилей;
  • "DIMSTYLE" - таблица размерных стилей;
  • "UCS" - таблица именованных систем координат;
  • "VIEW" - таблица именованных видов;
  • "VPORT" - таблица конфигураций видовых экранов;
  • "APPID" - таблица имен приложений.

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

(5etq lay1 (tbinext "LAYER" T)) - возвращает список с данными первого слоя рисунка (первым слоем должен быть слой с именем "0"), например: ((0 . "LAYER") (2 . "0") (70 . 0) (62 . 7) (6 . "Continuous")); в этом списке в точечной паре с DXF-кодом 0 находится имя таблицы, в которой ищется неграфический объект, с кодом 2 - имя слоя, с кодом б - тип линий примитивов слоя по умолчанию (т. е. каким типом отображать объекты с типом линии ПОСЛОЮ (BYLAYER)), с кодом 62 - цвет слоя по умолчанию, 70 - состояние слоя по отношению к операциям блокирования, замораживания; нетрудно заметить, что аналогичные DXF-коды используются в списке, возвращаемом функцией entget для примитивов;

(setq lay2 (tbinext "LAYER")) - возвращает список с данными второго слоя рисунка, например: ((0 . "LAYER") (2 . "стена1") (70 . 4) (62 . 40) (6 . "ограждение1"));

(setq lay2name (tbiobjname "LAYER" "Стена1")) - возвращает <Имя объекта: 14аа570>; теперь с помощью функции entget можно получить тот же список, что и lay2 в предыдущем примере.

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

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

  • (dictadd <словарь> <символ> <новый>) - добавление нового объекта к словарю;
  • (dictnext <словарь> [<признак>]) - чтение очередного символа из словаря (аналогична функции tbinext, но работает со словарями);
  • (dictremove <словарь> <символ>) - удаление символа словаря;
  • (dictrename <словарь> <старое> <новое>) - переименование символа словаря;
  • (dictsearch <словарь> <символ> [<следующий>]) - поиск символа в словаре (аналогично функции tbisearch);
  • (layoutlist) - получение списка имен листов текущего рисунка;
  • (namedobjdict) - получение имени корневого словаря неграфических объектов рисунка;
  • (setview <вид> [<в экран>]) - установка вида в видовом экране;
  • (snvalid <имя>) - проверка имени таблицы символов на недопустимые знаки.

12.4.11. Функции, работающие с расширенными данными

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

Если расширенные данные присоединены к примитиву, то в базе рисунка они следуют за обычными данными (DXF-коды этих данных находятся в диапазоне от -2 до 239). Извлечь расширенные данные можно с помощью функции entget, при обращении к которой нужно указывать имя приложения, с которым они связаны (см. описание функции entget в разд. 12.4.9). В списке, возвращаемом функцией entget, расширенные данные находятся в подсписке, начинающемся с DXF-кода -3 (признак наличия расширенных данных), в котором далее располагаются точечная пара с кодом 1001 (начало расширенных данных и имя приложения, с которым они связываются) и точечные пары с DXF-кодами 1000, 1002-1071. Назначение DXF-кодов расширенных данных описывается в табл. 12.6.

Таблица 12.6. Назначение DXF-КОДОВ расширенных данных

Код

Назначение

1000

Строковая константа длиной не более 255 знаков (256-й знак зарезервирован под символ с кодом 0)

1001

Строковая константа, используемая только для указания имени приложения, длиной не более 31 знака (если код 1001 попадает внутрь списка, организуемого с помощью DXF-КОДОВ 1002, то он интерпретируется как обычная константа, а не имя приложения; см. далее описание DXF-кода 1002). Имя приложения должно состоять только из цифр, латинских букв и символов

1003

Имя слоя, с которым связываются расширенные данные

1005

Метка объекта в базе чертежа

1010

Трехмерная точка (три вещественных числа)

1040

Вещественное число

1070

16-битовое целое число (со знаком или без знака)

1071

32-битовое целое число со знаком (длинное целое). Хотя система AutoCAD хранит данные группы с кодом 1071 как длинное целое, AutoLISP возвращает их как вещественные числа. Функциям entmake и entmod в точечной паре с кодом 1071 можно подавать либо целые числа, либо вещественные. ObjectARX трактует данные группы 1071 как длинные целые

1002

Строка, принимающая значения "{" или "}" и имеющая тот же смысл, что и левая и правая круглые скобки в обозначении списка. С помощью группы с кодом 1002 можно формировать в расширенных данных списковые структуры (они должны начинаться открывающей скобкой с кодом 1002, затем должны идти данные, включаемые в список, а закрывающая скобка с кодом 1002 завершает оформление списка). См. также замечание об интерпретации данных группы 1001 в таком списке

1004

Двоичные данные длиной не более 127 байт. Обрабатываются только в ObjectARX

1011

Трехмерная точка, интерпретируемая как положение в МСК. Такая точка перемещается, масштабируется, поворачивается и симметрируется одновременно с родительским примитивом рисунка. Если точка попадает в рамку выбора команды РАСТЯНУТЬ (STRETCH), то она подвергается операции растягивания вместе с родительским примитивом

1012

Трехмерная точка, интерпретируемая как перемещение в МСК. Такая точка не перемещается и не растягивается одновременно с основным примитивом, но участвует вместе с ним в операциях масштабирования, поворота и симметрирования

1013

Трехмерная точка, интерпретируемая как направление в МСК. Такая точка не масштабируется, не перемещается и не растягивается одновременно с основным примитивом, но участвует вместе с ним в операциях поворота и симметрирования. Вектор с координатами, взятыми из группы с кодом 1013, является нормализованным, т. е. единичной длины

1041

Вещественное число, интерпретируемое как расстояние. Оно масштабируется одновременно с родительским примитивом

1042

Вещественное число, интерпретируемое как масштабный коэффициент. Масштабируется одновременно с родительским примитивом



Как было сказано выше, расширенные данные связываются с именем конкретного приложения. Имена приложений хранятся в рисунке в таблице символов "APPID" (см. разд. 12.4.10). Чтобы занести имя приложения в эту таблицу, следует пользоваться функцией rеgарр:

(rеgарр <приложение>)

Параметр <приложение> должен быть текстовой строкой (по возможности нужно выбирать имя приложения таким, чтобы оно не совпадало с именами приложений других разработчиков - иначе это приведет к неправильной работе с расширенными данными). Функция rеgарр возвращает nil в случае ошибки (nil возвращается также, если приложение с таким именем уже регистрировалось).

Функция entmake (описание см. в разд. 12.4.9) может создать примитив и сразу присоединить к нему расширенные данные. С помощью функции entmod можно добавить расширенные данные к существующему графическому объекту.

Предположим в качестве примера, что к последнему существующему примитиву рисунка (пусть им является отрезок) нужно добавить расширенные данные, связанные с приложением "GENHULL":

(setq le (entget (entlast) ) ) - сохраняет в переменной le список последнего примитива, у которого еще нет расширенных данных: ((-1 . <Имя объекта: 14аа578>) (0 . "LINE") (330 . <Имя объекта: 14aa4f8>) (5 . "2F") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (62 . 1) (100 . "AcDbLine") (10 85.4655 223.335 0.0) (11 187.712 167.209 0.0) (210 0.0 0.0 1.0));

(setq edata '((-3 ("GENHULL" (1000 . "Пластмасса") (1070 . 57))))) - сохраняет в переменной edata список с расширенными данными, которые будут добавлены к списку le (добавляются текстовая строка с DXF-кодом 1000 и целое число с DXF-кодом 1070);

(setq le2 (append le edata)) - объединяет списки le и edata и формирует новый список le2: ((-1 . <Имя объекта: 14аа578>) (0 . "LINE") (330 . <Имя объекта: 14aa4f8>) (5 . "2F") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (62 . 1) (100 . "AcDbLine") (10 85.4655 223.335 0.0) (11 187.712 167.209 0.0) (210 0.0 0.0 1.0) (-3 ("GENHULL" (1000 . "Пластмасса") (1070 . 57))));

(entmod le2) - модифицирует примитив по новому списку и возвращает то же значение, что и предыдущее выражение;

(entget (entlast) '("GENHULL")) - получает список нового последнего примитива вместе с расширенными данными, относящимися к приложению "GENHULL": ((-1 . <Имя объекта: 14аа578>) (0 . "LINE") (330 . <Имя объекта: 14aa4f8>) (5 . "2F") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (62 . 1) (100 . "AcDbLine") (10 85.4655 223.335 0.0) (11 187.712 167.209 0.0) (210 0.0 0.0 1.0) (-3 ("GENHULL" (1000 . "Пластмасса") (1070 . 57)))).

Размер расширенных данных любого примитива не должен превышать 16 килобайт (16 383 байта). Поэтому по мере добавления таких данных их размер нужно контролировать. Этой цели служат две функции:

  • (xdsize <список>) - получает размер в байтах, необходимый для сохранения расширенных данных; аргумент <список> - это список с расширенными данными, начинающийся с DXF-кода -3;
  • (xdroom <примитив>) - возвращает целое число - количество свободных байтов в зоне расширенных данных примитива.

Перед записью в зону примитива новой порции расширенных данных нужно проверить, достаточно ли для них места.

12.4.12. Другие функции

Коротко рассмотрим другие функции языка AutoLISP.

Функция alert позволяет вывести на экран диалоговое окно с сообщением системы AutoCAD. Синтаксис функции:

(alert <сообщение>)

Функция возвращает nil. Максимальная длина строки <сообщение> зависит от многих вещей (в частности, от платформы) и может быть вычислена пользователем самостоятельно. В случае превышения допустимой длины AutoCAD обрезает сообщение. При необходимости вывести сообщение в несколько строк нужно использовать знаки конца строки ("\n").

Пример:

(setq lines (strcat "Я вас любил: любовь еще, быть может,\n"

"В душе моей угасла не совсем;\nНо пусть она вас больше не тревожит;\n"

"Я не хочу печалить вас ничем."))

(alert lines) выводит на экран окно, изображенное на рис. 12.5.

Рис. 12.5. Диалоговое окно, вызываемое функцией alert

В данном примере выведены четыре строки, поскольку трижды был использован знак конца строки. Выход из диалогового окна, изображенного на рис. 12.5, - щелчок по кнопке ОК.

Несколько полезных геометрических функций:

  • (inters <точка1> <точка2> <точка3> <точка4> [<признак>]) - если аргумент <признак> отсутствует или задан отличным от nil, функция вычисляет пересечение двух отрезков (первый имеет концы в точке] и точ-ке2, а второй - в точкеЗ и точке4, заданных соответствующими аргументами <точка1>, <точка2>, <точка3> И <точка4>); если аргумент <признак> задан и равен nil, то функция вычисляет пересечение двух прямых, проходящих через отрезки; если все аргументы-точки являются трехмерными, то функция inters ищет пересечение в трехмерном пространстве; если хотя бы одна из точек имеет только две координаты, то вычисляется пересечение проекций отрезков на текущую плоскость построений; точки задаются как списки из трех или двух вещественных чисел;
  • (polar <точка> <угол> <расстояние>) - возвращает координаты точки, которая отстоит от исходной точки, определяемой аргументом <точка> на заданное расстояние с помощью аргумента <расстояние>; вектор, идущий из исходной точки в вычисляемую новую точку, должен образовывать (в проекции на текущую плоскость построений) с осью Х заданный угол, определяемый аргументом <угол>, в радианах;
  • (textbox <список>) - возвращает список из двух точек, являющихся точками диагоналей прямоугольника, описанного вокруг надписи; надпись задается с помощью аргумента <список>, который должен иметь формат списка текстового примитива (в том виде, в каком его вернула бы функция entget); если аргумент <список> не содержит каких-либо параметров, то функция textbox при вычислении дополняет его текущими установками рисунка;
  • (osnap <точка> <режим>) - возвращает результат применения к точке, заданной аргументом <точка> функции объектной привязки с установками режимов, заданными в аргументе <режим>; режимы привязки указываются с помощью строки, в которой без пробелов через запятую перечисляются наименования режимов: "_end", "_mid", "_int", "_nea", "_nod" и т. д.; на результат операции оказывает влияние значение системной переменной APERTURE.

Примеры:

(inters '(2.25 4.50) '(-2.25 6.335) '(1.27 0.50) '(-8.65 -2.30)) - возвращает nil;

(inters '(2.25 4.50) '(-2.25 6.335) '(1.27 0.50) '(-8.65 -2.30) nil) - возвращает (7.64593 2.29966);

(polar '(16.32 4.782) 0.345 4.79) - возвращает (20.8278 6.40196);

(osnap '(16.32 4.782) "_end,_mid") - возвращает координаты точки, уточненной с помощью применяемых одновременно функций объектной привязки к конечной и средней точкам.

К полезным функциям, кроме того, относятся функции работы с элементами меню:

  • menucmd - операции с пунктами меню;
  • menugroup - работа с группой меню.

Подробности описания этих функций в настоящей книге не приводятся (их можно найти в справочной системе AutoCAD).

В языке AutoLISP есть некоторое количество функций для работы с диалоговыми окнами (они тоже из-за недостатка места здесь не рассматриваются):

  • функции работы с диалогами - load_dialog, unload_dialog, start_dialog, done_dialog, term_dialog, new dialog;
  • функции работы С ПОЛЯМИ - action_tile, get_tile, set_tile, mode tile, get_attr, client_data_tile;
  • функции работы с графическим кнопками - slide_image, start_image, vector image, end_image, dimx_tile, dimy_tile, fill_image;
  • функции работы СО списками - start_list, end_list, add_list.

К рассматриваемой версии языка AutoLISP в качестве расширения могут быть добавлены более ста функций, реализующих технологию ActiveX и дополняющих возможности пользователя по созданию эффективных программных продуктов на базе системы AutoCAD 2000. Все эти функции начинаются с префиксов vir-, via- и vlax-, и перед первым обращением к любой из них надо выполнить функцию загрузки (без этого они не будут доступны):

(vl-load-com)

Технология ActiveX облегчает и ускоряет доступ к примитивам и их характеристикам. К примитивам рисунка можно прикрепить другие объекты, называемые реакторами. Реакторы отслеживают определенные будущие события (например, перемещение или удаление примитива, открытие, сохранение или закрытие рисунка, вставку блока или внешней ссылки). Как только проверяемое событие происходит, реакторы с помощью специальных средств выполняют запрограммированные операции.

Предыдущий раздел ! | Следующий раздел !

©2002 Малинин В.В. - редактор
электронной версии
©2002 ЦИТ СГГА - издатель
Все права защищены.