-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Design Automation tutorial review #98
base: master
Are you sure you want to change the base?
Changes from all commits
9e1b0b9
b82db86
8a0a583
03e583f
a49fd0b
a7be09c
9a774f9
8aebbe1
9c99d34
727281f
1107d91
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
# Define an Activity | ||
|
||
Activity is the specification of an action that can be executed using a specified engine. It specifies the number of input and output files, and the AppBundle and entry-point to use. | ||
Activity is the specification of an action that can be executed using a specified engine. It specifies: the number of input and output files, the AppBundle and an entry-point to use. | ||
|
||
In this tutorial sample, the activity has 2 inputs (file & JSON data) and 1 output (file). | ||
|
||
> It's worth mentioning again the Design Automation documentation for [entities](https://forge.autodesk.com/en/docs/design-automation/v3/developers_guide/field-guide/), where you can see the relation between them in [Entity Relationships](https://forge.autodesk.com/en/docs/design-automation/v3/developers_guide/field-guide/#entity-relationships) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thinking if this image help or not... my perception is that is too complicated, considering this is a basic tutorial, but open to suggestions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree it can be confusing to show this at the beginning of the tutorial, but this comment is done in purpose in an advanced moment of the tutorial, when creating the Activity, to clarify possible doubts with the API entities (Activity vs Engine vs Workitem vs AppBundle) and the relation between them. At this point, introducing the concept of activity, the rest of the items have to be clear, because in terms of logic-relation is the one which unites them :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe move that as a "learn more" in the first paragraph? so we keep the 1st paragraph as general info, the 2nd as the call to action. |
||
|
||
Choose your language: [Node.js](designautomation/activity/nodejs) | [.NET Core](designautomation/activity/netcore) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,10 +12,30 @@ To define the activity we'll need the executable and the default file extension. | |
/// </summary> | ||
private dynamic EngineAttributes(string engine) | ||
{ | ||
if (engine.Contains("3dsMax")) return new { commandLine = "$(engine.path)\\3dsmaxbatch.exe -sceneFile \"$(args[inputFile].path)\" $(settings[script].path)", extension = "max", script = "da = dotNetClass(\"Autodesk.Forge.Sample.DesignAutomation.Max.RuntimeExecute\")\nda.ModifyWindowWidthHeight()\n" }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was intentionally left in a single line, to keep it short, and considering this piece won't change much |
||
if (engine.Contains("AutoCAD")) return new { commandLine = "$(engine.path)\\accoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\" /s $(settings[script].path)", extension = "dwg", script = "UpdateParam\n" }; | ||
if (engine.Contains("Inventor")) return new { commandLine = "$(engine.path)\\inventorcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "ipt", script = string.Empty }; | ||
if (engine.Contains("Revit")) return new { commandLine = "$(engine.path)\\revitcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "rvt", script = string.Empty }; | ||
if (engine.Contains("3dsMax")) | ||
return new { | ||
commandLine = "$(engine.path)\\3dsmaxbatch.exe -sceneFile \"$(args[inputFile].path)\" $(settings[script].path)", | ||
extension = "max", | ||
script = "da = dotNetClass(\"Autodesk.Forge.Sample.DesignAutomation.Max.RuntimeExecute\")\nda.ModifyWindowWidthHeight()\n" | ||
}; | ||
if (engine.Contains("AutoCAD")) | ||
return new { | ||
commandLine = "$(engine.path)\\accoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\" /s $(settings[script].path)", | ||
extension = "dwg", | ||
script = "UpdateParam\n" | ||
}; | ||
if (engine.Contains("Inventor")) | ||
return new { | ||
commandLine = "$(engine.path)\\inventorcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", | ||
extension = "ipt", | ||
script = string.Empty | ||
}; | ||
if (engine.Contains("Revit")) | ||
return new { | ||
commandLine = "$(engine.path)\\revitcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", | ||
extension = "rvt", | ||
script = string.Empty | ||
}; | ||
throw new Exception("Invalid engine"); | ||
} | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,22 @@ | ||
# Prepare a plugin | ||
# Prepare an AppBundle (plugin) | ||
|
||
Design Automation uses .bundle just like the Autodesk App Store, meaning you need to create a `PackageContents.xml` and a ZIP with the `DLL` (and other required files). For detailed information on how to create them, please visit [Autodesk App Store Developer Center](https://www.autodesk.com/developer-network/app-store). | ||
At this section we will create a basic plugin or AppBundle that searches for the Windows in the scene model tree and updates the `width` and `height` parameters of it, saving the resulting file as a new file. | ||
|
||
At this section we will create a basic plugin that update `width` and `height` parameter and save the resulting file. Also the supporting files (`PackageContents.xml`) and the folder structure to place them. Finally create a .ZIP file ready to upload to Design Automation. | ||
Design Automation uses .bundle just like the Autodesk App Store. For it, a `PackageContents.xml` descriptor file will be created and ZIP together with the `DLL` and other possible required files. For detailed information on how to create them, please visit [Autodesk App Store Developer Center](https://www.autodesk.com/developer-network/app-store). The created ZIP AppBundle file will be uploaded. | ||
|
||
### Prerequisites | ||
|
||
- **7zip**: use to create the .ZIP with bundle files, please install [from here](https://www.7-zip.org/). This tutorial assumes **7zip** is installed on the default folder: _C:\Program Files\7-Zip\7z.exe_. | ||
|
||
### Additional prerequisites | ||
#### Additional prerequisites | ||
|
||
For the next session you can use the pre-build plugin. Or if you decide to build it, you will need: | ||
|
||
- **Visual Studio**: Visual Studio 2017 or newer is required, please visit [this link](https://visualstudio.microsoft.com/vs/). | ||
|
||
- **AutoCAD, Inventor, Revit or 3ds Max**: In order to develop, test and debug your Design Automation plugin: [AutoCAD](https://www.autodesk.com/products/autocad/overview) | [Inventor](https://www.autodesk.com/products/inventor/overview) | [Revit](https://www.autodesk.com/products/revit/overview) | [3ds Max](https://www.autodesk.com/products/3ds-max/overview). | ||
- **AutoCAD, Inventor, Revit or 3ds Max**: In order to develop, compile, test and debug your Design Automation plugin, you will need the respective application installed: [AutoCAD](https://www.autodesk.com/products/autocad/overview) | [Inventor](https://www.autodesk.com/products/inventor/overview) | [Revit](https://www.autodesk.com/products/revit/overview) | [3ds Max](https://www.autodesk.com/products/3ds-max/overview). | ||
|
||
*** | ||
|
||
For the next step, choose the **Engine**, which is the Autodesk application where you plugin will run. You'll need the respective application installed in order to compile, debug and test locally. | ||
|
||
Choose the engine: [AutoCAD](/designautomation/appbundle/engines/autocad) | [Inventor](/designautomation/appbundle/engines/inventor) | [Revit](/designautomation/appbundle/engines/revit) | [3ds Max](/designautomation/appbundle/engines/max) | ||
The **Engine** is the Autodesk application where your plugin or App will run. Choose the engine you will use: | ||
[AutoCAD](/designautomation/appbundle/engines/autocad) | [Inventor](/designautomation/appbundle/engines/inventor) | [Revit](/designautomation/appbundle/engines/revit) | [3ds Max](/designautomation/appbundle/engines/max) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# Upload app bundle | ||
# Create and upload AppBundle | ||
|
||
Now the ZIP bundle is ready, let's upload to Design Automation. | ||
Now that the ZIP AppBundle is ready, let's upload it to Design Automation. | ||
|
||
Choose your language: [Node.js](designautomation/appbundle/nodejs) | [.NET Core](designautomation/appbundle/netcore) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,11 @@ Remember that for Design Automation, there should be no UI or prompts that canno | |
|
||
## Create a new .NET project | ||
|
||
Right-click on the solution, the **Add** >> **New Project**. Select **Windows Desktop**, then **Class Library** and, finally, name it `UpdateMAXParam`. You will then need to reference the Autodesk.Max.Dll managed assembly (3ds Max .NET API core module). This module is found in the 3dsmax.exe folder and when referencing, make sure to turn off the "Copy Local" flag. There are a few other modules used for .NET API support (see [The 3ds Max .NET SDK](http://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__developer_3ds_max__net_sdk_html)), but for this tutorial we will use only Autodesk.Max.dll. Then search and install `Newtonsoft.Json` (which is used to parse input data in JSON format). | ||
Right-click on the solution, and then **Add** >> **New Project**. Select **Windows Desktop**, then **Class Library** and, finally, name it `UpdateMAXParam`. | ||
|
||
You will then need to reference the Autodesk.Max.dll managed assembly (3ds Max .NET API core module). This module is found in the 3dsmax.exe folder and when referencing, make sure to turn off the "Copy Local" flag. There are a few other modules used for .NET API support (see [The 3ds Max .NET SDK](http://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__developer_3ds_max__net_sdk_html)), but for this tutorial we will use only Autodesk.Max.dll. | ||
|
||
Then search and install `Newtonsoft.Json` (which is used to parse input data in JSON format). | ||
|
||
> Please select .NET Framework 4.7. If not listed, [please install the Dev Pack](https://dotnet.microsoft.com/download/dotnet-framework/net47). | ||
|
||
|
@@ -28,9 +32,61 @@ As a result, the **package.config** should look like the following for the Newto | |
|
||
The project should contain a `Class1.cs` class, let's rename the file to `Command.cs` (for consistency). | ||
|
||
## PackageContents.xml | ||
|
||
Create a folder named `UpdateMAXParam.bundle` and inside this folder add a file named `PackageContents.xml` that will be the AppBundle descriptor. Copy the content listed below in the XML section into the PackageContents.xml file. | ||
|
||
This file will tell 3ds Max the modules to load. In this case points to the .NET API plugin assembly we will compile, but it can also include MAXScripts, Python, and/or C++ plugins. Because the dll plugin is being loaded through this feature, you only need to worry later about the instructions to trigger your automation job. Please note that a unique ID for both ProductCode and UpgradeCode are required for 3ds Max to correctly load your code. | ||
|
||
> You can learn about the [PackageContents.xml Format Reference](http://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__developer_writing_plug_ins_packaging_plugins_packagexml_format_html). | ||
> For more 3ds Max specific information for packaging your 3ds Max plugins, please see here [Packaging Plugins](http://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__developer_writing_plug_ins_packaging_plugins_html) | ||
|
||
|
||
```xml | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<ApplicationPackage | ||
SchemaVersion="1.0" | ||
AutodeskProduct="3ds Max" | ||
Name="Sample Design Automation Plugin for 3ds Max" | ||
Description="A sample package to update parameters of a 3ds Max scene file containing a casement window" | ||
AppVersion="2019.0.0" | ||
FriendlyVersion="2019.0.0" | ||
ProductType="Application" | ||
SupportedLocales="Enu" | ||
AppNameSpace="apps.autodesk.com" | ||
Author="Autodesk Forge" | ||
ProductCode="{6A8D06F4-C3DD-42DD-A69E-9B9617A7ABC0}" | ||
UpgradeCode="{CE88CEA5-47F6-423E-B9EC-E9FA683B5228}" | ||
> | ||
|
||
<CompanyDetails Name="Autodesk" | ||
Phone=" " | ||
Url="http://forge.autodesk.com" | ||
Email="[email protected]" /> | ||
|
||
<RuntimeRequirements OS="Win64" Platform="3ds Max" SeriesMin="2019" SeriesMax="2021" /> | ||
|
||
<Components Description="assemblies parts"> | ||
<RuntimeRequirements OS="Win64" Platform="3ds Max" SeriesMin="2019" SeriesMax="2021" /> | ||
<ComponentEntry AppName="UpdateMAXParam" Version="2019.0.0" ModuleName="./Contents/UpdateMAXParam.dll" AppDescription="The Sample Design Automation Plugin managed assembly module" /> | ||
</Components> | ||
|
||
</ApplicationPackage> | ||
``` | ||
|
||
Create a subfolder named `Contents` and leave it empty. At this point, the project should look like: | ||
|
||
![](_media/designautomation/max/bundle_folders.png) | ||
|
||
## Commands.cs | ||
|
||
This is the main code that will run with 3ds Max. Copy the following content into `Command.cs`. There are three classes to handle the Design Automation porcessing. First is the `InputParams` that will be used to interface with the JSON input data. Next is `ParameterChanger` class that is used to iterate the scene, and find all Casement Windows (but could be any object types as identified by the class ids). Finally the `RuntimeExecute` is used to take the input and drive the automation. Also note there is a specialized logging that will output information to the Design Automation console. See the LogTrace function. Note that the `ILogSys` 3ds Max managed class is used for this, and the flags used with the `LogEntry` API indicated are necessary for the output to show in the Design Automation console. | ||
This is the main code that will run within 3ds Max. Copy the following content into `Command.cs`. There are three classes to handle the Design Automation processing. | ||
|
||
1. `InputParams` will interface with the JSON input data. | ||
2. `ParameterChanger` iterates through the scene, and find all Casement Windows models in our sample. It could also be any object types as identified by the class ids. | ||
3. `RuntimeExecute` takes the input and drives the automation. | ||
|
||
Note there is a specialized logging that will output information to the Design Automation console. See the `LogTrace` function. Note that the `ILogSys` 3ds Max managed class is used for this, and the flags used with the `LogEntry` API indicated are necessary for the output to be shown in the Design Automation console. | ||
|
||
```csharp | ||
using System; | ||
|
@@ -182,48 +238,6 @@ namespace Autodesk.Forge.Sample.DesignAutomation.Max | |
} | ||
``` | ||
|
||
## PackageContents.xml | ||
|
||
Create a folder named `UpdateMAXParam.bundle` and inside this folder add a file named `PackageContents.xml`. Copy the content listed below in the XML section into the PackageContents.xml file. Learn more at the [PackageContents.xml Format Reference](https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-Customization/files/GUID-BC76355D-682B-46ED-B9B7-66C95EEF2BD0-htm.html). For more 3ds Max specific information for packaging your 3ds Max plugins see here [Packaging Plugins](http://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__developer_writing_plug_ins_packaging_plugins_html) | ||
|
||
This file will tell 3ds Max the modules to load (in this case the .NET API plugin assembly we are creating, but can also include MAXScripts, Python, and/or C++ plugins.) Because the plugin is being loaded through this feature, you only need to worry about the instructions to trigger your automation job. Please note that a unique ID for both ProductCode and UpgradeCode are required for 3ds Max to correctly load your code. See above mentioned documentation for details. | ||
|
||
```xml | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<ApplicationPackage | ||
SchemaVersion="1.0" | ||
AutodeskProduct="3ds Max" | ||
Name="Sample Design Automation Plugin for 3ds Max" | ||
Description="A sample package to update parameters of a 3ds Max scene file containing a casement window" | ||
AppVersion="2019.0.0" | ||
FriendlyVersion="2019.0.0" | ||
ProductType="Application" | ||
SupportedLocales="Enu" | ||
AppNameSpace="apps.autodesk.com" | ||
Author="Autodesk Forge" | ||
ProductCode="{6A8D06F4-C3DD-42DD-A69E-9B9617A7ABC0}" | ||
UpgradeCode="{CE88CEA5-47F6-423E-B9EC-E9FA683B5228}" | ||
> | ||
|
||
<CompanyDetails Name="Autodesk" | ||
Phone=" " | ||
Url="http://forge.autodesk.com" | ||
Email="[email protected]" /> | ||
|
||
<RuntimeRequirements OS="Win64" Platform="3ds Max" SeriesMin="2019" SeriesMax="2021" /> | ||
|
||
<Components Description="assemblies parts"> | ||
<RuntimeRequirements OS="Win64" Platform="3ds Max" SeriesMin="2019" SeriesMax="2021" /> | ||
<ComponentEntry AppName="UpdateMAXParam" Version="2019.0.0" ModuleName="./Contents/UpdateMAXParam.dll" AppDescription="The Sample Design Automation Plugin managed assembly module" /> | ||
</Components> | ||
|
||
</ApplicationPackage> | ||
``` | ||
|
||
Finally, create a subfolder named `Contents` and leave it empty. At this point, the project should look like: | ||
|
||
![](_media/designautomation/max/bundle_folders.png) | ||
|
||
## Post-build event | ||
|
||
> For Node.js it is required to adjust the AppBundle ZIP output folder. | ||
|
@@ -236,7 +250,7 @@ del /F "$(ProjectDir)..\forgesample\wwwroot\bundles\UpdateMAXParam.zip" | |
"C:\Program Files\7-Zip\7z.exe" a -tzip "$(ProjectDir)../forgesample/wwwroot/bundles/UpdateMAXParam.zip" "$(ProjectDir)UpdateMAXParam.bundle\" -xr0!*.pdb | ||
``` | ||
|
||
This will copy the DLL from /bin/debug/ into .bundle/Contents folder, then use [7zip](https://www.7-zip.org/) to create a zip, then finally copy the ZIP into /bundles folders of the webapp. | ||
This will copy the compiled DLL from /bin/debug/ into .bundle/Contents folder. It will then use [7zip](https://www.7-zip.org/) to create a zip. And finally it will copy the ZIP into /bundles folders of the webapp. | ||
|
||
![](_media/designautomation/max/post_build.png) | ||
> Note how the **Post-build event** uses the project and folder names, so make sure you're using these names. | ||
|
@@ -245,6 +259,8 @@ If you build the `UpdateMAXParam` project now you should see something like belo | |
|
||
![](_media/designautomation/max/build_output.png) | ||
|
||
## Testing locally | ||
|
||
At this point, you could test the functionality using the 3ds Max batch tool. It works similarly to the 3ds Max Design Automation engine and is a good way to test all your automation locally before sending the job to the Forge DA cloud services. For .NET Classes to be instantiated in MAXScript environment, we can use the `dotNetClass` MAXScript function. For this sample project, the MAXScript code would look like this: | ||
|
||
```MAXScript | ||
|
@@ -257,7 +273,7 @@ fn UpdateParam = | |
UpdateParam() | ||
``` | ||
|
||
To execute this locally, we could do test a a command-line prompt with something like this: | ||
To execute this locally, we could do test a command-line prompt with something like this: | ||
```CommandLine | ||
"%ADSK_3DSMAX_x64_2019%\3dsmaxbatch.exe" -sceneFile <myTestScene>.max da_script.ms | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, maybe we should keep it consistent, upper case (AppBundle, Activity, Workitem)