Pull to refresh

C# и AutoCAD. Некоторые приемы работы

Reading time7 min
Views21K

Цель данной статьи.


Целью данной статьи является рассмотрение некоторых приемов работы в связке Autocad + C#.
В основном буду опираться на статью «Начало работы с Autocad с помощью C#». В рамках данной статьи будут рассмотрены некоторые замечания по особенностям работы с Autocad с помощью SDK — ObjectARX.

Сразу оговорюсь, что НЕ являюсь квалифицированным программистом, и увлекаюсь программированием только как хобби. Так что в комментариях прошу указать на неточности и ошибки в изложении материала.

0. Несколько слов о .net API и ObjectARX в частности.


Вот что говорит нам .Net Developer Guide (в переводе bushman, см. литературу):
AutoCAD .NET API позволяет вам управлять приложением AutoCAD и файлами чертежей на программном уровне с использованием доступных сборок или библиотек. Эти объекты могут быть доступны для множества различных языков программирования и всевозможных сред разработки программного обеспечения.


Для работы с Autocad можно использовать библиотеки напрямую из Autocad (как это сделано в «Начало работы с Autocad с помощью C#»), либо использовать ObjectARX.

ObjectARX — это большой набор библиотек, предназначенный для разработки приложений для AutoCAD в среде программирования Microsoft Visual C++. Сам AutoCAD разработан с использованием ObjectARX.


«Чистый» ObjectARX предназначен для работы с Autocad с помощью C++, однако часть библиотек предстваляют собой ни что иное, как обертки для классов ObjectARX для работы через .net.

ObjectARX общедоступен и его можно скачать с сайта Autodesk.
Кроме того, по этому же адресу можно скачать обширную документацию по SDK.

Внимание! Необходимо использовать одинаковые версии ObjectARX и Autocad! Совместимость работы библиотеки одной версии с Autocad другой версии не гарантируется. Так что при изменении версии используемого Autocad необходимо перекомпилировать Вашу программу с новыми библиотеками! Кроме того, советую обратить внимание на совместимость различных версий ObjectARX и MS VS! Все описанные ниже примеры написаны для Autocad 2009, соответственно используется ObjectARX 2009, MS Visual Studio 2008.

1. Способы взаимодействия Autocad и C# посредством .Net API.


Существует два основных способа взаимодействия Autocad и C#:
  • 1. Программа реализуется в виде отдельного исполняемого файла с работой с файлами Autocad через COM-интерфейсы библиотеки Autocad.Interpop.Common. Данный прием позволяет получить обычный исполняемый exe-файл, который будет работать с dwg-файлами через COM. Данный способ имеет свое право на существование, однако, весьма ограничен функционально из-за малого числа доступных способов «воздействия» на чертеж и не рекомендуется в большинстве случаев.
  • 2. В виде расширения (plugin) autocad. Результатом работы будет dll-файл, который подгружается в Autocad командой «netload» и определяет новые команды (операции) и/или новое поведение стандартных операций.

В данной статье будет использовать второй способ.

2. Возможности ObjectARX


Набор библиотек ObjectARX представляет разработчику огромный набор инструментов как для работы чертежами, так и с окнами Autocad.

Основные возможности предоставляемые ObjectARX:
  • создание нового файла чертежа;
  • редактирование существующих чертежей, которое включает в себя: редактирование примитивов, блоков, словарей чертежа (см. «Начало работы с Autocad с помощью C#»),
  • добавление новых команд;
  • изменение интерфейса Autocad (добавление новых кнопок, панелей, закладок);

и т.д.

Подробнее о ObjectArx можно почитать в документации (в папке ObjectARX\docs\), так же в составе документации по ObjectARX есть примеры (папка \ObjectARX\samples\).

3. Примеры


Ниже в данной статье будет рассмотрено несколько примеров работы с Autocad и по каждому примеру будут даны небольшие комментарии.

В программах используются 2 библиотеки: AcDbMgd.dll и AcMgd.dll из папки \ObjectARX\inc-win32\. Их необходимо добавить к Reference проекта C#.

Для просмотра результата, необходимо в Autocad вызвать команду «netload» (без кавычек), загрузить получившуюся в результате компиляции dll-сборку и вызвать имя новой команды (addEntity и addBlock соответственно, регистр роли не играет).

3.1. Добавление новых примитивов в существующий чертеж

Код примера 1
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;


namespace clExample
{
    public class clExample
    {
        [CommandMethod("addEntity")] // название команды, вызываемой в Autocad
        public void addEntity()
        {
            // Сначала получаем БД текущего чертежа
            Database dbCurrent = Application.DocumentManager.MdiActiveDocument.Database;

            // Для работы, связанной с примитивами рекомендуется использовать транзакции:
            using (Transaction trAdding = dbCurrent.TransactionManager.StartTransaction())
            {
                // создаем новый примитив и определяем его основные свойства
                Circle cNewCircle = new Circle();
                cNewCircle.Center = new Point3d(0, 0, 0);
                cNewCircle.Radius = 100;
                cNewCircle.ColorIndex = 5;

                // получаем текущее пространство чертежа (может быть модель или лист)
                BlockTableRecord btrCurrSpace = trAdding.GetObject
                        (dbCurrent.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

                // добавляем в текущее пространство наш созданный примитив
                ObjectId oidCircle = btrCurrSpace.AppendEntity(cNewCircle);
                trAdding.AddNewlyCreatedDBObject(cNewCircle, true);

                //завершаем транзакцию
                trAdding.Commit();
            }
        }

    }
}



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

Результат примера 1



2. Создание блока и изменение его свойств

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

Код примера 2
[CommandMethod("createBlock")] // название команды, вызываемой в Autocad
        public void createBlock()
        {
            // сначала получаем БД текущего чертежа
            Database dbCurrent = Application.DocumentManager.MdiActiveDocument.Database;

            // и его редактор
            Editor edCurrent = Application.DocumentManager.MdiActiveDocument.Editor;

            // для работы, связанной с примитивами рекомендуется использовать транзакции:
            using (Transaction trAdding = dbCurrent.TransactionManager.StartTransaction())
            {
                // получаем таблицу блоков данного чертежа
                BlockTable btTable = (BlockTable)trAdding.GetObject(dbCurrent.BlockTableId, OpenMode.ForRead);

                // формируем опции запроса пользователя на ввод имени блока
                PromptStringOptions psoOpt = new PromptStringOptions("\nВведите имя блока: ");
                psoOpt.AllowSpaces = true;
                string strBlockName = "";
                // далее осуществляется проверка на корректность имени блока
                do
                {
                    // формируем запрос с заданными опциями
                    PromptResult prRes = edCurrent.GetString(psoOpt);
                    
                    // имя пользователя не введено. Прерываем работу
                    if (prRes.Status != PromptStatus.OK)
                        return;

                    try
                    {
                        // проверка на корректность символов в имени блока

                        SymbolUtilityServices.ValidateSymbolName(
                          prRes.StringResult,
                          false
                        );

                        // и нет ли блока с таким именем
                        if (btTable.Has(prRes.StringResult))
                            edCurrent.WriteMessage("\nA block with this name already exists.");
                        else
                            // ура, имя блока осилили :)
                            strBlockName = prRes.StringResult;
                    }
                    catch
                    {
                        edCurrent.WriteMessage("\nInvalid block name.");
                    }

                } while (strBlockName == "");

                // создаем ОПРЕДЕЛЕНИЕ блока  
                // создаем примитивы, которые будет содержать блок
                Line lNewLine = new Line();
                lNewLine.StartPoint = new Point3d(0, 0, 0);
                lNewLine.EndPoint = new Point3d(50, 50, 0);
                lNewLine.ColorIndex = 3;
                
                Circle cNewCircle = new Circle();
                cNewCircle.Center = new Point3d(0, 0, 0);
                cNewCircle.Radius = 100;
                cNewCircle.ColorIndex = 5;

                // создаем определение аттрибута
                AttributeDefinition adAttr = new AttributeDefinition();
                adAttr.Position = new Point3d(0, 0, 0);
                adAttr.Tag = "ATTRDEF"; 


                // создаем новое определение блока
                BlockTableRecord btrRecord = new BlockTableRecord();

                btrRecord.Name = strBlockName;

                btTable.UpgradeOpen();

                // добавляем его в таблицу блоков
                ObjectId btrId = btTable.Add(btrRecord);
                trAdding.AddNewlyCreatedDBObject(btrRecord, true);

                // добавляем в определение блока примитивы
                btrRecord.AppendEntity(lNewLine);
                trAdding.AddNewlyCreatedDBObject(lNewLine, true);

                btrRecord.AppendEntity(cNewCircle);
                trAdding.AddNewlyCreatedDBObject(cNewCircle, true);

                // и аттрибут
                btrRecord.AppendEntity(adAttr);
                trAdding.AddNewlyCreatedDBObject(adAttr, true);

                // теперь создадим экземпляр блока на чертеже
                // получаем пространство модели
                BlockTableRecord btrModelSpace = (BlockTableRecord)trAdding.GetObject(
            btTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite );

                // создаем новый экземпляр блока на основе его определения
                BlockReference brRefBlock = new BlockReference(Point3d.Origin, btrId);

                // добавляем экземпляр блока в базу данных пространства модели
                btrModelSpace.AppendEntity(brRefBlock);
                trAdding.AddNewlyCreatedDBObject(brRefBlock, true);

                // задаем значение аттрибуета
                AttributeReference arAttr = new AttributeReference();
                arAttr.SetAttributeFromBlock(adAttr, brRefBlock.BlockTransform);
                arAttr.TextString = "Атрибут!";
                brRefBlock.AttributeCollection.AppendAttribute(arAttr);
                trAdding.AddNewlyCreatedDBObject(arAttr, true);

                // закрываем транзакцию
                trAdding.Commit();               
            }
        }



Данный пример иллюстрирует процесс создания более сложных объектов — блоков. Процесс создания блоков следующий:

1) создаем определение блока (как элемент таблицы BlockTable) и добавляем его в таблицу блоков (не забываем проверить корректность имени блока);
2) создаем и добавляем в определение блока примитивы и определения атрибутов блока;
3) создаем экземпляр блока (BlockReference) и добавляем его в базу данных того пространства, которое нас интересует (в примере — пространство модели);
4) задаем значения атрибутов.

Все, блок готов.

Результат примера 2



Злоключение


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

Литература


through-the-interface.typepad.com — блог Kean Walsmley, сборник отличных примеров;
spiderinnet1.typepad.com — блог spiderinnet1, еще один блог с примерами;
sites.google.com/site/bushmansnetlaboratory — частичный перевод на русский язык Autocad Net developer Guide
www.theswamp.org — англоязычный форум по Autocad .net. Рассмотрено много примеров.
www.caduser.ru — русскоязычный форум. Часто заглядывают и подсказывают настоящие гуру программирования на .net. Чрезвычайно полезный ресурс.
forums.autodesk.com — официальный форум Autocad англоязычный форум (отсутствие подсветки и разметки синтаксиса просто выламывает глаза).
Autocad Net Developer Giude — основная литература при создании приложения для Autocad.
forum.dwg.ru — еще один русскоязычный форум, посвященный Autocad (спасибо BoxaShu)
Tags:
Hubs:
+17
Comments14

Articles