Отправляет email-рассылки с помощью сервиса Sendsay

Программирование в AutoCAD

  Все выпуски  

Программирование в AutoCAD


Информационный Канал Subscribe.Ru

Здравствуйте, уважаемые мои коллеги и друзья!

Представление объектов в чертеже AutoCAD (продолжение)

Visual Basic for Application (VBA)

AutoCAD через VBA предоставляет объектную модель, хорошо описанную в файле помощи (AutoCAD Visual LISP and ActiveX Help). Доступ к примитивам (то, собственно, о чем сейчас у нас идет речь) осуществляется следующим образом. Существует объект верхнего уровня AcadApplication. Он содержит коллекцию Documents, которая позволяет нам получить доступ ко всем открытым документам текущего сеанса работы. Каждый открытый файл представлен объектом AcadDocument - членом этой коллекции.

Получить доступ к текущему (активному) чертежу можно по-разному. Во-первых, AcadDocument имеет свойство Active, информирующее нас о том, активен ли данный документ или нет. Во-вторых, можно прямо обратиться к активному документу через AcadApplication.ActiveDocument, или, что тоже самое, через объект ThisDrawing.

На самом деле, есть небольшая разница между ActiveDocument и ThisDrawing. Для глобальных VBA-проектов (в смысле доступа из различных файлов, а не масштабности замысла) разницы нет никакой, если мы программно не переключаемся между открытыми документами. Но можно создавать встроенные (embedded) VBA-проекты, которые являются частью какого-либо отдельного DWG-файла. В этом случае ThisDrawing всегда ссылается на документ, содержащий данный проект, а ActiveDocument - на документ, активный в данный момент времени.

Объект AcadDocument содержит две коллекции: ModelSpace и PaperSpace со ссылками на объекты чертежа AcadEntity, расположенные в пространстве модели и пространстве листа соответственно.

Таким образом, объектную модель AutoCAD, касаемо объектов чертежа, можно представить следующей схемой:

Application --> Documents
                    |
                Document --> ModelSpace, PaperSpace
                    |                   |
                   ...              AcadEntity
                                        |
                                    AcadEntity
                                        |
                                    AcadEntity
                                        |
                                       ...

Соответственно, алгоритм перебора всех примитивов, находящихся, скажем, в пространстве модели, можно представить так:

Dim Ent As AcadEntity
For Each Ent In ThisDrawing.ModelSpace
    ...
    ' Некоторые действия над объектом
    ...
Next Ent

Необходимо учесть, что объект AcadEntity предоставляет свойства и методы, общие для всех примитивов: имя слоя, тип линии и т.д. Чтобы получить доступ к специфическим свойствам конкретного примитива (отрезка, дуги и пр.), надо воспользоваться специальными объектами для этих примитивов (AcadLine, AcadArc, ...). Например, в чертеже построен отрезок, и нам надо узнать его длину:

Dim Ent As AcadEntity, Lin As AcadLine, Leng As Double
' Перебираем все примитивы
For Each Ent In ThisDrawing.ModelSpace
    ' Ищем объект нужного нам типа
    Select Case TypeName(Ent)
        Case "IAcadLine"
            ' Присваиваем ссылку на искомый объект
            ' специализированной переменной
            Set Lin = Ent
            ' Измеряем длину
            Leng = Lin.Length
    End Select
Next Ent

Замечание: для того, чтобы наши изменения свойств примитива нашли отражение в чертеже AutoCAD, необходимо после сделанных изменений выполнить метод Update данного объекта, который приблизительно соответствует LISP-функции entmod.

Некоторые итоги

Мы рассмотрели действия над объектами чертежа с помощью Visual LISP и Visual Basic. Сразу виден ряд отличий, заключенных не в особенностях этих языков, а в подходе к представлению данных чертежа. Перечислю их:

  • LISP работает с данными чертежа именно в том виде, в котором они представлены физически в памяти компьютера и в DWG-файле. Располагая хорошим арсеналом функций, ориентированных на работу со списками, программист имеет возможность эффективно, одной-двумя строками кода, делать выборки нужных данных, модифицировать, склеивать, разъединять и сортировать массивы данных.
  • VBA стандартизирует программирование Windows-приложений вообще и AutoCAD в частности. А это значит, что человек с опытом программирования на VBA, изучив в короткие сроки объектную модель AutoCAD, может писать полноценные приложения для этой системы. Другое дело - такое программирование подразумевает хорошее знание AutoCAD в качестве пользователя, но это уже другой вопрос.
  • LISP всегда являлся и является по сей день встроенным языком программирования, когда как VBA для AutoCAD - нечто внешнее. Отсюда - заметный даже на быстрых компьютерах выигрыш LISPа в скорости загрузки программ и исполнения длинных циклов, более "суровое" отношение к распределению и использованию памяти.
  • VBA, как универсальное средство обмена данными между Windows-приложениями, незаменим там, где необходим этот самый обмен данными. Например, обращение к базам данных, к документам MS Word или, скажем, к трехмерной модели детали, выполненной в SolidWorks или 3D Studio Max - все это возможно почти исключительно средствами VBA.

Это - далеко не полный список преимуществ и недостатков обоих рассматриваемых нами языков. Являясь давним и верным поклонником LISPа, я старался как можно более объективно оценивать и LISP, и VBA. Двигаясь дальше, я надеюсь, мы с вами будем пополнять этот список.


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

А диалог уже начался. И я открываю первым письмом с вопросами раздел под названием

Вопросы и ответы

Вопрос следующий:

Здравствуйте, Алексей.

  Я новичок в AutoCAD и в LISP тоже, и хотелось бы увидеть рассылку по
  Vislual LISP.

  Также я хотел задать вопрос по примеру программы:

  Насколько я понял, команда setq <оп1> <оп2> устанавливает значение
  <оп1> в <оп2> (как set  в Tcl). entmod делает изменения на чертеже.
  А вот строчку:
    (setq obj_data (subst (cons 8 "NEW") (assoc 8 obj_data) obj_data))
  я не очень понял (начиная с subst).

  Расскажите поподробнее про комманды subst cons assoc ?
  

-- 
С уважением,
 ldmitry 

Здравствуйте, ldmitry! Спасибо за вопрос, ибо понимание этих моментов - пожалуй, ключ ко всему программированию на LISPе.

Функция subst производит замену (substitution) одного из элементов списка, и имеет следующий формат:
(subst новый_элемент_списка старый_элемент_списка список)
и возвращает список с измененным элементом. Например:

;;; Формируем список целых чисел:
(setq my_list '(1 2 3 4 5 6))
;;; Функцией subst меняем 3 на 10:
(subst 10 3 my_list)
;;; LISP возвратит следующий список:
(1 2 10 4 5 6)

Функция assoc производит поиск нужного подсписка в сложном списке (т.е. в списке, состоящем из списков, пардон за тавтологию) по первому элементу подсписка, и возвращает найденный подсписок или NIL, если таковой не найден:

;;; Формируем следующий список:
(setq my_list '((1 2) (3 4) (5 6)))
;;; Функцией assoc находим подсписок с первым элементом, равным 3:
(assoc 3 my_list)
;;; LISP возвратит следующий список:
(3 4)

Перед тем, как познакомиться с функцией cons, надо дать пояснения к двум понятиям, специфичным для LISPа: атом и точечная пара. Атомом называют любой символ (переменную или константу), значение которого не является списком или NIL. А точечная пара - это особый список, состоящий из двух атомов, разделенных точкой, например: (8 . "NEW"). Особенностью точечной пары является то, что при использовании функции cdr (которая для обычного списка возвращает весь список без первого элемента) для точечной пары возвращается второй атом.

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

Функция cons формирует список: (cons атом список_или_атом). Если второй параметр - список, то атом добавляется в начало этого списка, если же второй параметр - атом, то формируется точечная пара.

(cons 1 '(2 3))
;;; Возвращает список (1 2 3)
(cons 1 2)
;;; Возвращает точечную пару (1 . 2)

Таким образом, возвратившись к вопросу о примере из предыдущей рассылки:

(setq obj_data (subst (cons 8 "NEW") (assoc 8 obj_data) obj_data)),
где:
(cons 8 "NEW") формирует точечную пару (8 . "NEW"), которая должна заменить старый подсписок в obj_data с DXF-кодом 8.
(assoc 8 obj_data) возвращает этот самый старый подсписок в obj_data с DXF-кодом 8. В нашем случае это было (8 . "0")
Итак, как мы уже видим, вся эта конструкция для того, чтобы изменить подсписок в obj_data с кодом 8 на нужный нам (8 . "NEW").

Надеюсь, я ответил на Ваш вопрос.

С вами был Алексей Краутер.

Свои вопросы, советы и пожелания присылайте на subscribe@craidell.ru

Ваши наиболее интересные письма будут опубликованы в данной рассылке. Если вы не желаете публикацию вашего письма, пожалуйста, укажите это в теле письма.

До свидания!

Количество подписчиков: 70



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное