Список работ

Управление примитивами Автокада средствами Автолиспа

Содержание

Введение

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

Так, в нижеприведенном коде

(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

Вкладка 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 изображение блока.

Блок с измененными атрибутом at1 и невидимым атрибутом at2

Рис. 3. Блок с программно измененными атрибутами

Замечание. Для восстановления видимости скрытого атрибута можно употребить команду ATTDISP с опцией ON.

Построение блок схем

В разделе приводятся этапы, которые следует реализовать при создании помощника для построения блок-схем вычислительных алгоритмов:

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

Пример линейной схемы. Записать линейную схему алгоритма поиска первого четного отличного от нуля элемента одномерного массива.

  1. Начало.
  2. Ввод массива X из N элементов. Тестовый набор: N = 7; X = -1, 0, 3, 4, 9, 8, -4.
  3. Найден = ложь;
  4. Для k = 1 по N цикл
      lmnt = X[k]
      Если lmnt <> 0 и mod(lmnt, 2) = 0 Тогда
       firstEven = lmnt
       Найден = истина
       Выход из цикла;
      КонецЕсли
     КонецЦикла
  5. Если Найден Тогда
      Напечатать firstEven
     Иначе
      Напечатать "В векторе нет четных отличных от нуля элементов"
     КонецЕсли;
  6. Останов.

Заключение

Приведенные сведения могут быть полезны при создании приложений, обеспечивающих известную степень автоматизации создания рисунка и его последующей обработки. Например, создать библиотеку элементов блок-схем вычислительных алгоритмов, проработать процедуры их вставки с одновременной прорисовкой нужных связей. Также можно написать AutoLISP-код, обеспечивающий преобразование линейной схемы алгоритма в рисунок Автокада с соответствующей блок-схемой. Может быть решена и обратная задача: генерация линейной схемы по рисунку Автокада, содержащего созданную по установленным правилам блок-схему.

П1. Задачи для построения блок-схем

В заданном векторе (одномерном массиве) найти:

  1. Первый и второй отрицательные элементы.
  2. Разность первого и последнего нечетного элементов.
  3. Индексы наименьшего и наибольшего элементов.
  4. Наименьшую сумму вида x2i + x2i+1, где xi - элемент вектора x.
  5. Произведение трех наименьших элементов вектора.
  6. Сумму элементов вектора с четными индексами.
  7. Наибольший отрицательный и наименьший элементы.
  8. Первый положительный и последний отрицательный элементы.
  9. Число отрицательных элементов с нечетными индексами.
  10. Число элементов, расположенных после его наибольшего отрицательного элемента.
  11. Сумму положительных, меньших заданного числа элементов.
  12. Наибольшее произведение вида x2i * x2i+1, где xi - элемент вектора x.
  13. Число элементов, равных наибольшему элементу вектора.
  14. Индекс максимального отрицательного элемента.
  15. Первую пару соседних элементов с разным знаком.
  16. Разность между произведением положительных элементов и суммой модулей отрицательных элементов.
  17. Количество четных отрицательных элементов.
  18. Среднее арифметическое первого положительного и последнего отрицательного элементов.
  19. Число равных нулю элементов, расположенных перед наименьшим положительным элементом.
  20. Сумму двух наименьших элементов.
  21. Наибольшую сумму вида xi + xn-i+1, где xi - элемент массива x, а n - число его элементов.
  22. Количество отрицательных, отличных от заданной величины элементов.
  23. Произведение нечетных отрицательных элементов.
  24. Число первых подряд идущих элементов, отсортированных в порядке возрастания их значений.
  25. Число положительных элементов, предшествующих первому отрицательному элементу.
  26. Число равных нулю элементов, расположенных после наименьшего нечетного элемента.
  27. Произведение первого и последнего четного элементов.
  28. Сумму положительных, меньших заданной величины элементов.
  29. Разность абсолютных значений наибольшего и наименьшего элементов.
  30. Число нулевых элементов, предшествующих последнему положительному элементу.

Литература

  1. AutoCAD® 2013 Help.
  2. Гладков С. А. Программирование на языке Автолисп в системе САПР Автокад. М.: "Диалог-МИФИ", 1991. - 96 с.

Список работ

Рейтинг@Mail.ru