ADN Open CIS
Сообщество программистов Autodesk в СНГ

11/01/2019

Введение в Design Automation для Inventor

Что нам понадобится:

- Inventor SDK и Visual Studio 2017 для сборки нашего плагина для Inventor

                - см. документацию в SDK, доступную при установке Inventor-а

                - можно использовать Visual Studio Community Edition

- клиент HTTP для вызова Forge API

                - мы будем использовать синтаксис postman и cURL

                - если Вы предпочитаете работать с графическим UI, все примеры cURL в этой статье могут быть импортированы в postman

Этап 1. Плагин для Inventor

Если у Вас возникли проблемы с этой частью, Вы можете пропустить этот этап. Здесь ZIP-файл нашего плагина со всеми исходниками: InventorThumbnailAddin.zip.

Дополнение: Здесь доступен шаблон проекта Visual Studio, позволяющий ускорить разработку плагина для Inventor.

Установите Inventor SDK, откройте Visual Studio и создайте новый проект с AddIn-ом для Inventor-а на основе шаблона Autodesk Inventor AddIn. Мы назовем его InventorThumbnailAddin:

Создайте новый файл в проекте Automation.cs, определите в нём класс Automation:

Код - C#: [Выделить]
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Inventor;
  4.  
  5. namespace InventorThumbnailAddin
  6. {
  7.     [ComVisible(true)]
  8.     public class Automation
  9.     {
  10.         InventorServer m_server;
  11.  
  12.         public Automation(InventorServer server)
  13.         {
  14.             m_server = server;
  15.         }
  16.  
  17.         public void Run(Document document)
  18.         {
  19.             string documentFolder = System.IO.Path.GetDirectoryName(document.FullFileName);
  20.             string imageFilename = System.IO.Path.Combine(documentFolder, "thumbnail.bmp");
  21.             if (document.DocumentType == DocumentTypeEnum.kPartDocumentObject)
  22.             {
  23.                 Camera camera = m_server.TransientObjects.CreateCamera();
  24.                 camera.SceneObject = (document as PartDocument).ComponentDefinition;
  25.                 camera.ViewOrientationType = ViewOrientationTypeEnum.kIsoTopRightViewOrientation;
  26.                 camera.ApplyWithoutTransition();
  27.                 camera.SaveAsBitmap(imageFilename, 256, 256, Type.Missing, Type.Missing);
  28.             }
  29.         }
  30.  
  31.         public void RunWithArguments(Document document, NameValueMap args)
  32.         {
  33.             Run(document);
  34.         }
  35.     }
  36. }

В файле StandardAddInServer.cs (который должен быть автоматически создан по шаблону проекта Autodesk Inventor AddIn) и измените его следующим образом (но сохраните GUID, который был сгенерирован):

Код - C#: [Выделить]
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Inventor;
  4.  
  5. namespace InventorThumbnailAddin
  6. {
  7.     [GuidAttribute("YOUR GUID")]
  8.     public class StandardAddInServer : Inventor.ApplicationAddInServer
  9.     {
  10.         private InventorServer m_server;
  11.         private Automation m_automation;
  12.  
  13.         public StandardAddInServer()
  14.         {
  15.         }
  16.  
  17.         #region ApplicationAddInServer Members
  18.  
  19.         public void Activate(Inventor.ApplicationAddInSite addInSiteObject, bool firstTime)
  20.         {
  21.             m_server = addInSiteObject.InventorServer;
  22.             m_automation = new Automation(m_server);
  23.         }
  24.  
  25.         public void Deactivate()
  26.         {
  27.             Marshal.ReleaseComObject(m_server);
  28.             m_server = null;
  29.  
  30.             GC.Collect();
  31.             GC.WaitForPendingFinalizers();
  32.         }
  33.  
  34.         public void ExecuteCommand(int commandID)
  35.         {
  36.         }
  37.  
  38.         public dynamic Automation
  39.         {
  40.             get
  41.             {
  42.                 return m_automation;
  43.             }
  44.         }
  45.  
  46.         #endregion
  47.     }
  48. }

Затем найдите addin-файл Inventor-а (Autodesk.InventorThumbnailAddin.Inventor.addin) и замените его содержимое (опять же, используя Ваши GUID):

Код - XML: [Выделить]
  1. <Addin Type="Plugin">
  2.   <ClassId>{YOUR GUID}</ClassId>
  3.   <ClientId>{YOUR GUID}</ClientId>
  4.   <DisplayName>Inventor Thumbnail Addin</DisplayName>
  5.   <Description>Addin for generating thumbnail images from Inventor part files.</Description>
  6.   <Assembly>InventorThumbnailAddin.dll</Assembly>
  7. </Addin>

Откройте свойства проекта, на вкладке Build Events замените команды Post-build на следующие:

Код - HTML: [Выделить]
  1. call "%VS140COMNTOOLS%vsvars32" x86
  2. mt.exe -manifest "$(ProjectDir)InventorThumbnailAddin.X.manifest" -outputresource:"$(TargetPath)"
  3. XCopy "$(ProjectDir)Autodesk.InventorThumbnailAddin.Inventor.addin" "$(TargetDir)" /y

для подписи нашей DLL и копирования её и соответствующего addin-файла.

Теперь мы можем собрать проект, сгенерировав необходимые файлы в папке bin/Debug. Мы будем использовать их в Forge Design Automation.

 

Этап 2. Forge Design Automation

Для начала обсудим базовые концепции, которые используются этим сервисом. Согласно документации есть 4 основных типов объектов: engines, app bundles, activities и work items:

- Engine - это те приложения, которые обрабатывают Ваши задачи в облаке, например, Revit или Inventor

- App bundle - набор файлов (обычно бинарных), используемых для выполнения определенных задач при помощи доступных engines

- Activity - что-то вроде шаблона задачи, определяющих входные и выходные данные, app bundle, с помощью которого будет выполняться задача

- work item - экземпляр задачи с конкретными входными и выходными данными (обычно URL, откуда и куда должны быть загружены исходные/результирующие файлы)

Еще одна очень важная вещь, которую необходимо понять: каждый объект app bundle/activity/work item может иметь несколько версий и для того, чтобы правильно ссылаться на конкретными объект, Вам необходимо создать что-то вроде псевдонима (alias) - строку, определяющую конкретную версию объекта. Что-то вроде git tags. Например, когда Вы создаете вторую версию activity GenerateThumbnail, создается endpoint (мы будем использовать их позже), которому мы назначим alias "prod", указывающий на эту конкретную версию. Затем для того, чтобы сослаться на данную версию activity, мы будем использовать её имя + alias, например GenerateThumbnail+prod. Более того, в некоторых случаях, будет использоваться префикс с точкой, например YhryNMLor4R1maFhY4zER8unpISoP5E4.GenerateThumbnail+prod. Эта строка полностью идентифицирует объект и Вас в качестве его владельца.

Итак, мы разобрались с основными концепциями, поехали!

Получение токена доступа

Мы будем использовать токен двухфакторной авторизации для выполнения всех запросов к сервисам Forge. Обратитесь к этому пошаговому руководству, где детально расписано получение токена двухфакторной авторизацию. Большая часть Design Automation API требует только scope code:all, но в рассматриваемом нами примере нам так же необходимо создавать bucket-ы и другие обхекты с использование Data Management API, поэтому также добавьте следующие scope: bucket:create, bucket:read, data:create, data:read и data:write.

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   https://developer.api.autodesk.com/authentication/v1/authenticate \
  3.   -H 'Content-Type: application/x-www-form-urlencoded' \
  4.   -d 'client_id=<Ваш CLIENT ID>&client_secret=<Ваш CLIENT SECRET>&grant_type=client_credentials&scope=bucket%3Acreate%20bucket%3Aread%20data%3Acreate%20data%3Aread%20data%3Awrite%20code%3Aall'

Скопируйте из результатов выполнения данного запроса тоекн доступа, и во всех последующих запросах, представленных в этой статье, замените <YOUR ACCESS TOKEN>

Создаем app bundle

Для начала, необходимо создать bundle нашего плагина для Inventor-а. Bundle - это zip-архив, содержащий папку с dll-файлами и файл PackageContents.xml, который описывает содержимое этой папки. В нашем примере нам нужно взять скомпилированные файлы плагина Inventor-а, положить их в папку InventorThumbnailAddin.bundle так, как показано на рисунке:

и заархивировать её (в формате ZIP)

Обратите внимание, что файл PackageContents.xml находится в папке InventorThumbnailAddin.bundle, а не в папке Contents.

В файле PackageContents.xml мы описываем наш плагин, включая GUID и относительный путь к файлу манифеста (.addin). Вы можете также добавить дополнительную информацию об авторе/компании, создавшей плагин.

Код - XML: [Выделить]
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <ApplicationPackage SchemaVersion="1.0" Version="1.0" ProductCode="{YOUR GUID}" Name="..." Description="..." Author="...">
  3.     <CompanyDetails Name="..." Phone="..." Url="..." Email="..." />
  4.     <Components>
  5.         <!-- For Inventor Engine, "Platform" attribute must be "Inventor" -->
  6.         <RuntimeRequirements  OS="Win64" Platform="Inventor" />
  7.         <!-- For Inventor Plug-in, the "Module" attribute must point to the .addin manifest file. -->
  8.         <ComponentEntry LoadOnAutoCADStartup="False" LoadOnCommandInvocation="False"
  9.             AppDescription="Thumbnail App Package."
  10.             ModuleName="./Contents/Autodesk.InventorThumbnailAddin.Inventor.addin" AppName="InventorThumbnailAddin"/>
  11.     </Components>
  12.     <EnvironmentVariables>
  13.     </EnvironmentVariables>
  14. </ApplicationPackage>

Теперь, когда у нас есть файл InventorThumbnailAddin.bundle.zip, мы можем создать app bundle ThumbnailBundle - новый alias к его первой версии.

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   https://developer.api.autodesk.com/da/us-east/v3/appbundles \
  3.   -H 'Authorization: Bearer <YOUR ACCESS TOKEN>' \
  4.   -H 'Content-Type: application/json' \
  5.   -d '{
  6.                 "id": "ThumbnailBundle",
  7.                 "description": "Inventor plugin for generating thumbnails from IPT files.",
  8.                 "engine": "Autodesk.Inventor+23"
  9.   }'

Ответом сервера будет JSON со структурой, подобной этой:

Код - JSON: [Выделить]
  1. {
  2.     "uploadParameters": {
  3.         "endpointURL": "https://dasprod-store.s3.amazonaws.com",
  4.         "formData": {
  5.             "key": "...",
  6.             "content-type": "...",
  7.             "policy": "...",
  8.             "success_action_status": "200",
  9.             "success_action_redirect": "",
  10.             "x-amz-signature": "...",
  11.             "x-amz-credential": "...",
  12.             "x-amz-algorithm": "...",
  13.             "x-amz-date": "...",
  14.             "x-amz-server-side-encryption": "...",
  15.             "x-amz-security-token": "..."
  16.         }
  17.     },
  18.     "engine": "Autodesk.Inventor+23",
  19.     "description": "Inventor plugin for generating thumbnails from IPT files.",
  20.     "version": 1,
  21.     "id": "<OWNER ID>.ThumbnailBundle"
  22. }

В uploadParameters содержатся аргументы запроса, которые нам будут нужны для загрузки app bundle в облако, где сервисы Design Automation смогут их использовать. Выполните POST-запрос с полученным URL, включая все аргументы и zip-файл с созданным ранее bundle-ом.

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   https://dasprod-store.s3.amazonaws.com \
  3.   -H 'content-type: multipart/form-data' \
  4.   -F key=... \
  5.   -F policy=... \
  6.   -F content-type=... \
  7.   -F success_action_status=200 \
  8.   -F success_action_redirect= \
  9.   -F x-amz-signature=... \
  10.   -F x-amz-credential=... \
  11.   -F x-amz-algorithm=... \
  12.   -F x-amz-date=... \
  13.   -F x-amz-server-side-encryption=... \
  14.   -F x-amz-security-token=... \
  15.   -F file=@/path/to/your/zipfile

Если Вы не хотите загружать bundle из командной строки, Вы можете импортировать команду curl в postman, заполнить все поля на основе полученных uploadParameters, переключить тип последнего параметра (file) и выбрать файл для загрузки.

img https://flint-prodcms-forge.s3.amazonaws.com/prod/s3fs-public/inline-images/binaries-upload-postman.png

Наконец, для того, чтобы к нашему app bunlde можно было бы обратиться в последующих шагах, представленных в этой статье, нам нужно создать alias, назовем его prod для его первой версии:

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   https://developer.api.autodesk.com/da/us-east/v3/appbundles/ThumbnailBundle/aliases \
  3.   -H 'Authorization: Bearer <YOUR ACCESS TOKEN>' \
  4.   -H 'Content-Type: application/json' \
  5.   -d '{
  6.                 "id": "prod",
  7.                 "version": 1
  8.   }'

Определим activity

Затем нам нужно определить activity GenerateThumbnail, которая будет использовать ThumbnailBundle, принимая на входе один файл IPT и генерируя один BMP файл на выходе:

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   https://developer.api.autodesk.com/da/us-east/v3/activities \
  3.   -H 'Content-Type: application/json' \
  4.   -d '{
  5.     "commandLine": [
  6.         "$(engine.path)\\InventorCoreConsole.exe /i $(args[PartFile].path) /al $(appbundles[ThumbnailBundle].path)"
  7.     ],
  8.     "parameters": {
  9.         "PartFile": {
  10.             "verb": "get",
  11.             "description": "IPT file or ZIP with assembly to process"
  12.         },
  13.         "OutputBmp": {
  14.             "zip": false,
  15.             "ondemand": false,
  16.             "optional": true,
  17.             "verb": "put",
  18.             "description": "Generated thumbnail",
  19.             "localName": "thumbnail.bmp"
  20.         }
  21.     },
  22.     "engine": "Autodesk.Inventor+23",
  23.     "appbundles": ["<OWNER ID>.ThumbnailBundle+prod"],
  24.     "description": "Generate thumbnails for IPT files (Inventor 2019).",
  25.     "id": "GenerateThumbnail"
  26.   }'

Рассмотрим структуру отправляемого в запросе JSON-файла

- мы определяем id и описание activity

- мы определяем список app bundle-ов, которые будут использоваться (на забудьте заменить <OWNER ID> хэшем, полученным при создании app bundle), engine, который будет запускать создаваемую activity

- мы определяем входной параметр PartFile

                - activity известно, что этот параметр входной, т.к. мы указали GET значением свойства verb, мы будем указывать URL, откуда сервис должен будет взять файл

- мы определяем выходной параметр OutputBmp как файл thumbnail.bpm, который может быть (опционально) сгенерирован нашей activity

- мы указываем командную строку, которую будет запускать engine с нашими параметрами

                - синтаксис $(<something>.path) будет преобразован в актуальные пути engine, input/output файлов или app bundle-ов при запуске activity

Так же как для app bundle, мы должны создать alias, указывающий на первую версию нашей activity:

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   https://developer.api.autodesk.com/da/us-east/v3/activities/GenerateThumbnail/aliases \
  3.   -H 'Authorization: Bearer <YOUR ACCESS TOKEN>' \
  4.   -H 'Content-Type: application/json' \
  5.   -d '{
  6.                 "id": "prod",
  7.                 "version": 1
  8.   }'

Запуск work item

Перед запуском GenerateThumbnail activity, нам нужно подготовить url-ы исходного файла Inventor-а и bmp-файла, который должна сгенерировать наша activity. Можно использовать любые решения, позволяющие хранить файлы и обращаться к ним по URL, а так же иметь возможность загрузки файла по заданному URL. В нашем примере мы воспользуемся Data Management API, с помощью POST-запроса /oss/v2/buckets/:bucketKey/objects/:objectKey/signed создадим URL с доступом на чтение для файла Inventor-а (IPT) и второй URL с доступом на запись, куда будет загружаться сгенерированный файл thumbnail.bmp:

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   'https://developer.api.autodesk.com/oss/v2/buckets/<YOUR BUCKET KEY>/objects/<YOUR INPUT IPT FILENAME>/signed?access=read' \
  3.   -H 'Authorization: Bearer <YOUR ACCESS TOKEN>' \
  4.   -H 'Content-Type: application/json' \
  5.   -d '{}'

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   'https://developer.api.autodesk.com/oss/v2/buckets/<YOUR BUCKET KEY>/objects/<YOUR OUTPUT BMP FILENAME>/signed?access=readwrite' \
  3.   -H 'Authorization: Bearer <YOUR ACCESS TOKEN>' \
  4.   -H 'Content-Type: application/json' \
  5.   -d '{}'

Теперь создадим work item:

Код - HTML: [Выделить]
  1. curl -X POST \
  2.   https://developer.api.autodesk.com/da/us-east/v3/workitems \
  3.   -H 'Authorization: Bearer <YOUR ACCESS TOKEN>' \
  4.   -H 'Content-Type: application/json' \
  5.   -d '{
  6.     "activityId": "<OWNER ID>.GenerateThumbnail+prod",
  7.     "arguments": {
  8.         "PartFile": {
  9.             "url": "<YOUR INPUT FILE URL>",
  10.             "zip": false
  11.         },
  12.         "OutputBmp": {
  13.             "url": "<YOUR OUTPUT FILE URL>",
  14.             "verb": "put"
  15.         }
  16.     }
  17. }'

Ответом этого запроса будет что-то вроде:

Код - JSON: [Выделить]
  1. {
  2.     "status": "pending",
  3.     "stats": {
  4.         "timeQueued": "..."
  5.     },
  6.     "id": "<WORK ITEM ID>"
  7. }

Зная work item id, мы можем запросить её статус:

Код - HTML: [Выделить]
  1. curl -X GET \
  2. https://developer.api.autodesk.com/da/us-east/v3/workitems/<WORK ITEM ID> \
  3. -H 'Authorization: Bearer <YOUR ACCESS TOKEN>'

Если задача выполнена успешно, ответ будет иметь следующую структуру:

Код - JSON: [Выделить]
  1. {
  2.     "status": "success",
  3.     "reportUrl": "...",
  4.     "stats": {
  5.         "timeQueued": "...",
  6.         "timeDownloadStarted": "...",
  7.         "timeInstructionsStarted": "...",
  8.         "timeInstructionsEnded": "...",
  9.         "timeUploadEnded": "..."
  10.     },
  11.     "id": "<WORK ITEM ID>"
  12. }

В случае возникновения проблем, в поле reportUrl будет URL текстового файла с подробной информацией.

Вот, собственно, и всё. По второму URL ("<YOUR UPLOAD FILE URL>") будет доступен файл со сгенерированным изображением Вашего файла Inventor-а.

Источник: https://forge.autodesk.com/blog/simple-introduction-design-automation-inventor

Автор перевода: Александр Игнатович

Обсуждение: http://adn-cis.org/forum/index.php?topic=

Опубликовано 11.01.2019
Отредактировано 11.01.2019 в 16:51:50