Рассматриваются функции Автолиспа, обеспечивающие доступ к примитивам графической базы данных Автокада.
Функции позволяют:
Так, в нижеприведенном коде
(setq en (entlast))
(setq ed (entget en))
функция entlast возвращает последний введенный примитив (ссылку на этот примитив), а функция entget – описание этого примитива. К примеру, если последним введенным примитивом была линия, начинающаяся в точке [0, 0, 0] и завершающаяся в точке [200, 200, 0], то функция entget вернет список из пяти элементов:
((-1 . <Entity name: 7ffff705bc0>)
(0 . "LINE")
(330 . <Entity name: 7ffff7039f0>)
(5 . "234")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbLine")
(10 0.0 0.0 0.0)
(11 200.0 200.0 0.0)
(210 0.0 0.0 1.0)
)
Из примера видно, что описание элемента это список, содержащий подсписки - преимущественно точечные пары. Первый элемент подсписка содержит код (идентификатор) свойства примитива (в данном случае линии), а второй или последующие - это значение свойства. Так свойство с кодом 8 указывает на слой, в котором примитив расположен, а свойство с кодом 10 содержит начальные координаты линии, а с кодом 11 - ее конечные координаты.
Часть свойств может быть изменена. В частности, можно изменить слой или координаты вершин линии.
Также рассматриваются функции tblnext и tblsearch, обеспечивающие доступ к таблицам графической базы данных Автокада.
Для последующей проработки формулируется задача создания помошника построения блок-схем вычислительных алгоритмов, позволяющего вдобавок переводить блок-схему алгоритма в его линейную схему.
Обеспечивают следующие функции:
Функция | Описание |
---|---|
(entnext) | Возвращает первый введенный в рисунок примитив en |
(entnext en) | Возвращает примитив, введенный вслед за примитивом en |
(entlast) | Возвращает последний введенный в рисунок примитив |
(entsel [подсказка]) | Возвращает после выбора примитива мышью список (en pt), в котором en - это выбранный примитив, pt - точка выбора |
(entget en) | Возвращает список ed с описанием примитива en |
(entmod ed) | Обновляет описание ed примитива в графической базе данных |
(entupd en) | Обновляет отображение модифицированного примитива en. Употребляется при работе с вложенными примитивами |
(entdel en) | Удаляет из рисунка примитив en. При повторном употреблении примитив будет восстановлен |
С описанием ed примитива часто употребляются следующие функции:
Функция | Описание |
---|---|
(assoc k ed) | Возвращает подсписок, имеющийся в ed, первый элемент которого равен k |
(car ls) | Возвращает первый элемент списка ls |
(cdr ls) | Возвращает список ls без первого элемента, или второй элемент точечной пары ls |
(cons k ls) | Добавляет k в начало списка ls |
(subst (k value2) (k value1) ed) | Возвращает список ed, в котором подсписок (k value1) заменен на (k value2) |
Пример. Написать функцию, перемещающую начальную вершину линии вдоль оси Х на заданное значение.
(defun mvVrtX (x / ed en p pt)
(setq en (car (entsel "Select a line:")))
; Check primitive type
(if en
(progn
(setq ed (entget en))
(if (= (cdr (assoc 0 ed)) "LINE")
(progn
(setq p (assoc 10 ed)
pt (cdr p)
pt (cons (+ (car pt) x) (cdr pt))
ed (subst (cons 10 pt) p ed)
)
(entmod ed)
(alert "Done")
)
(alert "Line should be selected")
)
)
)
(princ)
)
Функцию можно набрать в редакторе Автолиспа (меню Tools - AutoLISP - Visual LISP Editor). Далее сохранить код, например, в файле c:\mvVrtX.lsp, который затем следует загрузить в командной строке Автокада
(load "c:/mvVrtX.lsp")
или воспользоваться меню Tools - Load Application.
Для перемещения вершины на 400 единиц по оси Х в командной строке следует набрать
(mvVrtX 400)
и нажать на Enter.
Задание. Написать функцию, перемещающую линию на другой слой рисунка.
Набор es примитивов возвращается функцией
(ssget [mode])
Некоторые варианты употребления функции:
(ssget) - последует предложение указать примитивы мышью: "Select objects:";
(ssget "L") - вернет набор с последним введенным в рисунок примитивом;
(ssget '(200 200 0)) - вернет набор примитивов, проходящих через точку (200 200 0);
(ssget "С" '(0 0) '(200 200)) - вернет набор примитивов, пересекаемых рамкой от (0 0) до (200 200);
(ssget "X" список фильтров) - вернет набор примитивов, отвечающих заданным фильтрам.
Каждый фильтр - это точечная пара, в котором первый элемент - это идентификатор свойства примитива, а второй - значение этого свойства. Например:
(ssget "X" '((8 . "gdb")))
вернет все примитивы, расположенные на слое "gdb".
А функция
(ssget "X" '((8 . "gdb") (0 . "INSERT")))
вернет все блоки, расположенные на слое "gdb".
Некоторые идентификаторы для фильтров ssget:
Идентификатор | Значение |
---|---|
0 | Тип примитива, например, "LINE" |
2 | Имя блока |
8 | Имя слоя |
62 | Индекс цвета (число от 0 до 256); при задании индекса 256, выбираются примитивы, имеющие цвет ByLayer (по слою), а при задании 0 - ByBlock (по блоку). Индексы цветов можно посмотреть в диалоге выбора цвета (рис. 1) на вкладке Index Color |
Рис. 1. Диалог выбора цвета примитива
Пример. Написать функцию, удаляющую все линии на слое "gdb", имеющие цвет с индексом 170 (синий цвет).
(defun dltBlGdb (/ es)
(setq es (ssget "X" '((0 . "LINE") (8 . "gdb") (62 . 170))))
(if es
(progn
(setvar "cmdecho" 0)
(command "_ERASE" es "")
(setvar "cmdecho" 1)
(alert "Done")
)
(alert "Empty")
)
(princ)
)
Работа с набором примитивов es ведется с помощью следующих функций:
Функция | Описание |
---|---|
(sslength es) | Возвращает число примитивов в наборе es |
(ssname es n) | Возвращает примитив en, имеющий в наборе es номер n (первый примитив в наборе имеет номер 0) |
(ssadd) | Возвращает пустой набор es |
(ssadd en es) | Добавляет в наборе es примитив en и возвращает пополненный набор |
(ssdel en es) | Удаляет примитив en из набора es и возвращает сокращенный набор |
(ssmemb en es) | Возвращает примитив en, если он имеется в наборе es, или nil - в противном случае |
Пример. Написать функцию, переносящую на слой "gdb" со слоя "0" линии, имеющие в наборе линий четные номера.
(defun ftchLns0Gdb (/ cntEs ed en es k)
(if (tblsearch "LAYER" "gdb")
(progn
(setq es (ssget "X" '((0 . "LINE") (8 . "0"))))
(if es
(progn
(setq k 0
cntEs (sslength es)
)
(while (< k cntEs)
(setq en (ssname es k)
ed (entget en)
ed (subst (cons 8 "gdb") (assoc 8 ed) ed)
)
(entmod ed)
(setq k (+ k 2))
)
(alert "Done")
)
(alert "Empty")
)
)
(alert "Layer 'gdb' not found")
)
(princ)
)
Таблицы графической базы данных хранят сведения о компонентах рисунка: его слоях, блоках, типах линий и пр.
Для получения данных, хранимых таблицами Автокада, употребляются функции tblnext и tblsearch.
К строке таблицы позволяет обратиться функция
(tblnext tn [f]),
в которой tn - это имя таблицы, например, "LAYER", "LTYPE", "BLOCK" и др.
Таблица с именем "LAYER" содержит строки с информацией о слоях рисунка, с именем "BLOCK" - о блоках рисунка и т. д.
Аргумент f задает порядок просмотра таблицы. Если аргумент задан и отличен от nil, то tblnext вернет первую строку таблицы, в противном случае tblnext вернет следующую за текущей строку таблицы.
Так, вызов
(tblnext "LAYER" T)
вернет первую строку таблицы слоев:
((0 . "LAYER") ; Имя таблицы
(2 . "0") ; Имя слоя
(70 . 0) ; Флаг состояния слоя (в данном случае видимый и текущий)
(62 . 7) ; Индекс цвета слоя
(6 . "Continuous") ; Тип линии (задана сплошная линия)
)
Функция tblnext вернет nil, если в таблице нет строк или если указатель переместился за пределы таблицы.
Функция
(tblsearch tn s [f])
вернет строку таблицы tn, в которой имеется в точечная пара (2 . s).
В зависимости от типа таблицы s - это имя слоя (таблица "LAYER"), или имя блока (таблица "BLOCK"), или имя типа линии (таблица "LTYPE") и т. д.
Если искомой точечной пары нет, то функция вернет nil.
Аргумент f определяет порядок последующего употребления функции tblnext: если f задан и отличен от nil, то tblnext, вызванная без параметра f, переместит указатель на строку, следующую за строкой, найденной tblsearch.
Пример 1. Создать несколько 9 слоев с именами "gdb1", "gdb2", ..., "gdb9". Вывести строки таблицы "LAYER", расположенные вслед за строкой с точечной парой (2 . "gdb6").
(defun prntSmLrs (/ k nm tRw)
(setq k 1)
(setvar "cmdecho" 0)
; Make layers first
(while (< k 10)
(setq nm (strcat "gdb" (itoa k))
k (1+ k)
)
(if (not (tblsearch "LAYER" nm)) (command "_layer" "_m" nm ""))
)
(setvar "cmdecho" 1)
; Find table row with dotted pair (2 . "gdb6")
(tblsearch "LAYER" "gdb6" T)
; Print next table rows
(while (setq tRw (tblnext "LAYER"))
(print tRw)
)
(princ)
)
Напечатает:
((0 . "LAYER") (2 . "gdb7") (70 . 0) (62 . 7) (6 . "Continuous"))
((0 . "LAYER") (2 . "gdb8") (70 . 0) (62 . 7) (6 . "Continuous"))
((0 . "LAYER") (2 . "gdb9") (70 . 0) (62 . 7) (6 . "Continuous"))
Пример 2. Вывести все строки таблицы "LAYER" (то есть сведения о все слоях рисунка).
(defun lLrs ( / tRw)
(print (tblnext "LAYER" T))
(while (setq tRw (tblnext "LAYER"))
(print tRw)
)
(print "Done")
(princ)
)
Задача рассматривается на следующем примере: функция mkBlckBn на базе примитива RECTANGLE создает блок bn с двумя атрибутами at1 и at2. Первому атрибуту задается значение R1, а второму - P68. Блок записывается в файл c:/bn.dwg и затем вставляется в центр рисунка. Функция attrMdfr меняет значение первого атрибута вставленного блока на R23 и делает второй атрибут блока невидимым.
; Создание блока с двумя атрибутами
(defun mkBlckBn ( )
(setq fn "c:/bn.dwg")
(setvar "cmdecho" 0)
; Delete all blocks
(if (setq es (ssget "_X" '((0 . "INSERT"))))
(command "_ERASE" es "")
)
(command "_LIMITS" '(0 0) '(160 120)
"_GRID" "_off"
"_ZOOM" "_W" '(0 0) '(160 120))
; Make a block first
(command "_RECTANGLE" '(0 0) '(60 30)
"_ATTDEF" "" "at1" "" "R1" "_m" '(30 15) 10 ""
"_ATTDEF" "" "at2" "" "P68" "_m" '(30 40) 10 ""
)
(if (findfile fn)
(command "_WBLOCK" fn "_y" "" '(0 0) "_w" '(-20 -20) '(61 50) "")
(command "_WBLOCK" fn "" '(0 0) "_w" '(-20 -20) '(61 50) "")
)
(command "_INSERT" fn '(50 45) "" "" "" "" "")
(setvar "cmdecho" 1)
(princ)
)
Вставленный блок показан на рис. 2.
Рис. 2. Вставлен блок, сохраненный в файле c:/bn.dwg
После вставки блока и выполнения
(setq en (entlast))
(entget en)
получим описание блока:
((-1 . <Entity name: 7ffff705bf0>)
(0 . "INSERT") ; Тип примитива
(330 . <Entity name: 7ffff7039f0>)
(5 . "237")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0") ; Слой
(100 . "AcDbBlockReference")
(66 . 1)
(2 . "bn") ; Имя блока
(10 50.0 45.0 0.0) ; Базовая точка вставки
(41 . 1.0)
(42 . 1.0)
(43 . 1.0)
(50 . 0.0)
(70 . 0)
(71 . 0)
(44 . 0.0)
(45 . 0.0)
(210 0.0 0.0 1.0)
)
Выполним далее
(setq en (entnext en))
(entget en)
получим описание последнего атрибута блока:
((-1 . <Entity name: 7ffff705c00>)
(0 . "ATTRIB") ; Тип примитива
(330 . <Entity name: 7ffff705bf0>) ; Родитель
(5 . "238")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbText")
(10 65.5006 69.3908 0.0)
(40 . 10.0)
(1 . "P68") ; Значение атрибута
(50 . 0.0)
(41 . 1.0)
(51 . 0.0)
(7 . "Standard")
(71 . 0)
(72 . 4)
(11 77.929 74.326 0.0)
(210 0.0 0.0 1.0)
(100 . "AcDbAttribute")
(280 . 0)
(2 . "AT2") ; Имя атрибута
(70 . 0)
(73 . 0)
(74 . 0)
(280 . 1)
)
Выполнив далее
(setq en (entnext en))
(entget en)
получим описание предшествующего атрибута блока (в нашем случае атрибута at1).
Выполнив вновь
(setq en (entnext en))
(entget en)
получим (в случае блока с двумя атрибутами) описание с типом примитива SEQEND:
((-1 . <Entity name: 7ffff705c20>)
(0 . "SEQEND")
(330 . <Entity name: 7ffff705bf0>) ; Родитель
(5 . "23A")
(100 . "AcDbEntity")
(67 . 0) (410 . "Model")
(8 . "0")
(-2 . <Entity name: 7ffff705bf0>)
)
Это означает, что все атрибуты исчерпаны.
Эти наблюдения позволяют записать следующую функцию, изменяющую атрибуты блока, как это предусмотрено заданием:
(defun attrMdfr ( / ed en)
(setq en (car (entsel "Select a block:")))
(if en
(progn
(setq ed (entget en))
(if (= (cdr (assoc 0 ed)) "INSERT")
(while (/= (cdr (assoc 0 ed)) "SEQEND")
(setq en (entnext en)
ed (entget en)
)
(cond ((= (cdr (assoc 2 ed)) "AT1")
(setq ed (subst (cons 1 "R23") (assoc 1 ed) ed)) ; Value would be changed
)
((= (cdr (assoc 2 ed)) "AT2")
(setq ed (subst (cons 70 1) (assoc 70 ed) ed)) ; Make it invisible
)
)
(entmod ed)
(entupd en)
)
(alert "Block should be selected")
)
)
)
(princ)
)
После выполнения функции получим приведенное на рис . 3 изображение блока.
Рис. 3. Блок с программно измененными атрибутами
Замечание. Для восстановления видимости скрытого атрибута можно употребить команду ATTDISP с опцией ON.
В разделе приводятся этапы, которые следует реализовать при создании помощника для построения блок-схем вычислительных алгоритмов:
Пример линейной схемы. Записать линейную схему алгоритма поиска первого четного отличного от нуля элемента одномерного массива.
Приведенные сведения могут быть полезны при создании приложений, обеспечивающих известную степень автоматизации создания рисунка и его последующей обработки. Например, создать библиотеку элементов блок-схем вычислительных алгоритмов, проработать процедуры их вставки с одновременной прорисовкой нужных связей. Также можно написать AutoLISP-код, обеспечивающий преобразование линейной схемы алгоритма в рисунок Автокада с соответствующей блок-схемой. Может быть решена и обратная задача: генерация линейной схемы по рисунку Автокада, содержащего созданную по установленным правилам блок-схему.
В заданном векторе (одномерном массиве) найти: