Я хочу написать серию tutorial-ов, демонстрирующих работу с архитектурными объектами с помощью Autodesk .NET API и Teigha Architecture. Начнем с самых азов: соберем и заставим работать упражнение “your first project” из документации к ACA, а затем немного расширим его для использования объектов Autodesk.Aec.Arch.DatabaseServices.Wall.
Для опытных программистов описание покажется длинным, но я считаю что первые шажки стоит описывать детально, чтобы исключить разночтения и дать возможность человеку без особых проблем запустить хотябы простейшее приложение. При дальнейшей работе проблем с ACA .NET API и так будет предостаточно.
Предыдущая моя статья, описывающая основы ACA,
Писать плагин я буду в VS2010 а проверять работу в ACA 2013 x64. Разные версии ACA могут требовать разные версии .NET Framework, кроме этого плагин, построенный для x32 не подгрузится ACA x64.
Шаг 1
Создаем проект Visual C# class library под названием AcaSample1 как показано на скриншоте. Версия .NET Framework у нас будет 4.
Шаг 2
Документация советует сразу добавить в references acmgd.dll и acdbmgd.dll с необходимыми для примера классами из ACA. Эти файлы лежат в корне папки, куда установлен ACA. У меня это C:\Program Files\Autodesk\AutoCAD 2013
Добавим нужные библиотеки как показано на скриншотах ( References -> Add reference -> вкладка browse )
Если все сделано правильно, в списке References появятся две новые библиотеки:
Далее, выделяем два добавленных референса, нажимаем на них правой кнопкой, идем в свойства и ставим им свойсво copy local в false. Это сделать необходимо, чтобы в будущем избежать трудноотлавливаемых глюков. Вот что пишет документация по этому поводу:
Setting Copy Local to False instructs Microsoft Visual Studio to not include the referenced DLL in the build output for the project. If the referenced DLL is copied to the build output folder, it can cause unexpected results when you load your assembly file in AutoCAD.
Шаг 3
Попробуем создать код команды так, как это предлагает документация. Сэмпл из ACA почему-то оперирует объектом MText а не архитектурными примитивами. Пройдем по примеру.
Добавляем директивы using:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
Добавляем код:
[assembly: CommandClass(typeof(AcaSample1.Class1))]
namespace AcaSample1
{
public class Class1
{
[CommandMethod("AdskGreeting")]
public void AdskGreeting()
{
// Get the current document and database, and start a transaction
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database; // Starts a new transaction with the Transaction Manager
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
// Open the Block table record for read //
BlockTable acBlkTbl;
acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
// Open the Block table record Model space for write
BlockTableRecord acBlkTblRec;
acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
/* Creates a new MText object and assigns it a location,
* text value and text style */
MText objText = new MText(); // Specify the insertion point of the MText object
objText.Location = new Autodesk.AutoCAD.Geometry.Point3d(2, 2, 0); // Set the text string for the MText object
objText.Contents = "Greetings, Welcome to the AutoCAD .NET Developer's Guide"; // Set the text style for the MText object
objText.TextStyleId = acCurDb.Textstyle; // Appends the new MText object to model space
acBlkTblRec.AppendEntity(objText); // Appends to new MText object to the active transaction
acTrans.AddNewlyCreatedDBObject(objText, true); // Saves the changes to the database and closes the transaction
acTrans.Commit();
}
}
}
}
Здесь AdskGreeting это имя команды. Впоследствии это имя нужно будет вводить в командной строке ACA, чтобы исполнить код функции AdskGreeting()
Пытаемся сбилдить… ну конечно, оно не билдится :)
Причина в том, что нам не хватает референсов, в которых определены CommandClass, CommandMethod и тд – accoremgd.dll
Эта библиотека тоже лежит в корне папки куда установлен ACA. Добавляем этот референс и ставим ему copy local в false:
Пробуем запустить билд: библиотека должна построиться без ошибок. В результате у нас получилась AcaSample1.dll
Шаг 4
Теперь нам надо обратить внимание на платформу. Например, дефолтная платформа в 2010 студии Debug \ AnyCPU, а у меня стоит Win 7 x64 и ACA x64. При попытке загрузить эту длл ACA x64 выдаст ошибку. Поэтому мне надо поменять целевую платформу:
Перестроим проект. На этом этапе должна получиться библиотека AcaSample1.dll в AcaSample1\AcaSample1\bin\x64\Debug
Документация еще советует проверить target framework
On the Applications tab, Target Framework drop-down list, select .NET Framework 4.0
но мы его выставляли на первом шаге при создании проекта.
Шаг 5
Пробуем загрузить наш плагин в ACA и выполнить команду. Открываем ACA 2013 и вводим в командной строке netload ( командную строку можно вызвать комбинацией ctrl + 9, если она скрыта ). Откроется диалоговое окно для выбора плагина ( правда если переменная FILEDIA у вас стоит в 0, то окно не откроется, а будет предложено ввести пусть до dll плагина в командной строке ). Идем в папку с солюшеном, ищем AcaSample1.dll ( у меня это AcaSample1\bin\x64\Debug ) и нажимаем open:
Если ошибок небыло, ACA промолчит. Набираем команду AdskGreeting. Если ошибок небыло, автокад опять промолчит, и, скорее всего, на экране ничего не изменится. Это потому что текст слишком мал или выходит из области, на которую направлена камера. Чтобы его увидеть используем команду zoom extents из панели (вкладка view):
В результате должны увидеть такое:
Ок. С небольшими дополнениями удалось построить и запустить базовый пример из документации к AutoCAD Architecture.
Шаг 6
Теперь попробуем сделать команду, которая использует собственно объекты ACA. Например, стены. Для этого заменим весь код примера на следующее (код кривоват, использовать только для пробы):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.Aec.Arch.DatabaseServices;
[assembly: CommandClass(typeof(AcaSample2_Walls.Class1))]
namespace AcaSample2_Walls
{
public class Class1
{
[CommandMethod("CreateHouse")]
public static void CreateHouse()
{
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;
acDoc.Editor.WriteMessage("\n CreateHouse command");
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
// Open the Block table record for read
BlockTableRecord acModelSpace = GetModelSpaceRecord(acCurDb, acTrans, OpenMode.ForWrite);
AddWallToModelSpace(new Point3d(0, 0, 0), new Point3d(5000, 0, 0), acModelSpace, acTrans);
AddWallToModelSpace(new Point3d(5000, 0, 0), new Point3d(5000, 5000, 0), acModelSpace, acTrans);
AddWallToModelSpace(new Point3d(5000, 5000, 0), new Point3d(0, 5000, 0), acModelSpace, acTrans);
AddWallToModelSpace(new Point3d(0, 5000, 0), new Point3d(0, 0, 0), acModelSpace, acTrans);
acTrans.Commit();
}
acDoc.SendStringToExecute("_-VIEW _SWISO ", true, false, false);
acDoc.SendStringToExecute("_.zoom _all ", true, false, false);
}
public static BlockTableRecord GetModelSpaceRecord(Database acDb, Transaction acTrans, OpenMode om)
{
// Open the Block table record for read
BlockTable acBlkTbl;
acBlkTbl = acTrans.GetObject(acDb.BlockTableId, OpenMode.ForRead) as BlockTable;
// Open the Block table record Model space for read
BlockTableRecord acBlkTblRec;
acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], om) as BlockTableRecord;
return acBlkTblRec;
}
private static void AddWallToModelSpace(Point3d ptS, Point3d ptE, BlockTableRecord acModelSpace, Transaction acTrans)
{
Wall w = new Wall();
w.Set(ptS, ptE, new Vector3d(0, 0, 1));
w.BaseHeight = 2500;
w.InstanceWidth = 300;
acModelSpace.AppendEntity(w);
acTrans.AddNewlyCreatedDBObject(w, true);
}
}
}
Мы написали новую команду CreateHouse, которая создает «дом» из четырех стен. В данном случае мы уже начали использовать объекты ACA, поэтому добавилась директива
using Autodesk.Aec.Arch.DatabaseServices;
Aec.Arch — это уже область архитектурных объектов.
Команды
acDoc.SendStringToExecute("_-VIEW _SWISO ", true, false, false);
acDoc.SendStringToExecute("_.zoom _all ", true, false, false);
поворачивают вид в изометрическую проекцию и делают вызов zoom_extents, который ранее мы делали руками в UI ACA.
Чтобы построить этот проект в references необходимо добавить библиотеки, в которых реализованы объекты ACA. В данном примере нам потребуются AecBaseMgd.dll и AecArchMgd.dll. Не забудьте также поставить поставить им свойство Copy local в false.
У меня эти библиотеки находятся в C:\Program Files\Autodesk\AutoCAD 2013\ACA\
Все, что начинается на Aec, относится к ACA.
Строим проект, подгружаем его с помощью netload в AutoCAD Architecture 2013 и выполняем команду CreateHouse. Должно получиться так:
Заключение
В данной статье я попробовал дать пошаговую инструкцию к первым попыткам программирования под ACA. Я знаю что тут есть похожие статьи про использование .NET API, но в данном случае мне захотелось изложить все подводящие шаги к использованию архитектурного API.
В следующих статьях я покажу как сделать ваше первое приложение с помощью Teigha Architecture, а затем перейду к разбору того, что же происходит в этих примерах: что такое dwg, что такое база данных куда мы добавляем стены, отличия архитектурных объектов от базовых примитивов автокада в плане работы с ними. Затем надеюсь рассмотреть более общие сценарии: как отрендерить архитектурные объекты в нужном представлении, как получить их геометрию для конвертации в другие форматы, как с ними работать и тд.
Комментарии (5)
imbeat
28.08.2015 13:58Еще бы ссылочку на документацию к API.
aabramovsky
28.08.2015 18:20Сам пример, который я разбираю, находится тут: для AutoCAD 2013 и для AutoCAD 2012
.NET API для Architecture довольно сырое. Я чуть позже соберу ссылки где я находил что-то для себя и добавлю. В основном я просто знаю какие объекты должны существовать и где примерно их искать, поэтому сразу ищу в сборках а не в документации
kedobear
28.08.2015 15:30Каков конечный функционал того, что вы планируете написать для ACA?
aabramovsky
28.08.2015 18:25Сейчас просто показать работу с основными объектами и механизмами (типа анкоров) на примере ACA и Teigha ( C++ ). Самое основное реальное требование, которое обычно возникает у меня в работе — это как импортировать или экспортировать объекты ACA в\из какого-то кастомного формата, который используется в приложении написанном сторонней фирмой.
Хотя есть и вопросы по самим API — как сделать что-то с объектами, как работать с display manager-ом и так далее.
Я надеюсь что тут будут задавать какие-то конкретные вопросы, тогда при возможности я напишу статьи на эти темы. Также интересно узнать у тех, кто сам работает с архитекчей, какие у них возникают потребности и запросы в работе.
imbeat
А создать Nuget-пакет, не?