-
Notifications
You must be signed in to change notification settings - Fork 7
/
Command.cs
155 lines (139 loc) · 6.64 KB
/
Command.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Autodesk Platform Services
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
/////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Autodesk.Max;
namespace Autodesk.Forge.Sample.DesignAutomation.Max
{
/// <summary>
/// Used to hold the parameters to change
/// </summary>
public class InputParams
{
public float Width { get; set; }
public float Height { get; set; }
}
/// <summary>
/// Changes parameters in automated way.
/// Iterate entire scene to get all nodes
/// In this example we specifically find Casement Windows by object class ID
/// Then modify the width and height based on inputs.
///
/// Could be expanded to find other window types, other objects, etc.
/// </summary>
static public class ParameterChanger
{
static List<IINode> m_sceneNodes = new List<IINode> { };
/// <summary>
/// Recursively go through the scene and get all nodes
/// Use the Autodesk.Max APIs to get the children nodes
/// </summary>
static private void GetSceneNodes(IINode node)
{
m_sceneNodes.Add(node);
for (int i = 0; i < node.NumberOfChildren; i++)
GetSceneNodes(node.GetChildNode(i));
}
/// <summary>
/// Function to specifically update Case Windows with input wedth and height parameters
/// </summary>
/// <param name="width">The new Width to set the Window</param>
/// <param name="height">The new Height to set the Window</param>
/// <returns>window count</returns>
static public int UpdateWindowNodes(float width, float height)
{
IGlobal globalInterface = Autodesk.Max.GlobalInterface.Instance;
IInterface14 coreInterface = globalInterface.COREInterface14;
IINode nodeRoot = coreInterface.RootNode;
m_sceneNodes.Clear();
GetSceneNodes(nodeRoot);
// 3ds Max uses a class ID for all object types. This is easiest way to find specific type.
// ClassID (1902665597L, 1593788199L) == 0x71685F7D, 0x5EFF4727 for casement window
IClass_ID cidCasementWindow = globalInterface.Class_ID.Create(0x71685F7D, 0x5EFF4727);
// Use LINQ to filter for windows only - in case scene has more than one,
// but this should still give us at least one for single window scene!
var sceneWindows = from node in m_sceneNodes
where ((node.ObjectRef != null) && // In some cases the ObjectRef can be null for certain node types.
(node.ObjectRef.ClassID.PartA == cidCasementWindow.PartA) &&
(node.ObjectRef.ClassID.PartB == cidCasementWindow.PartB))
select node;
// Iterate the casement windws and update the hight and width parameters.
foreach (IINode item in sceneWindows)
{
// window is using old-style ParamArray rather than newer ParamBlk2
IIParamArray pb = item.ObjectRef.ParamBlock;
pb.SetValue(0, coreInterface.Time, height); // window height is at index zero.
pb.SetValue(1, coreInterface.Time, width); // window width is at index one.
}
// If there are windows, save the window updates
int status;
if (sceneWindows.Count() > 0)
{
// The output file name must match what the Design Automation work item is specifying as output file.
string full_filename = coreInterface.CurFilePath;
string filename = coreInterface.CurFileName;
string new_filename = full_filename.Replace(filename, "outputFile.max");
status = coreInterface.SaveToFile(new_filename, true, false);
if (status == 0) //error
return -1;
}
// return how many windows were modified.
return sceneWindows.Count();
}
}
/// <summary>
/// This class is used to execute the automation. Above class could be connected to UI elements, or run by scripts directly.
/// This class takes the input from JSON input and uses those values. This way it is more cohesive to web development.
/// </summary>
static public class RuntimeExecute
{
static public int ModifyWindowWidthHeight()
{
int count = 0;
// Run entire code block with try/catch to help determine errors
try
{
// read input parameters from JSON file
InputParams inputParams = JsonConvert.DeserializeObject<InputParams>(File.ReadAllText("params.json"));
count = ParameterChanger.UpdateWindowNodes(inputParams.Width, inputParams.Height);
}
catch (Exception e)
{
LogTrace("Exception Error: " + e.Message);
return -1; //fail
}
LogTrace("Changed {0} window objects.", count);
return count; // 0+ means success, and how many objects were changed.
}
/// <summary>
/// Information sent to this LogTrace will appear on the Design Automation output
/// </summary>
private static void LogTrace(string format, params object[] args)
{
IGlobal globalInterface = Autodesk.Max.GlobalInterface.Instance;
IInterface14 coreInterface = globalInterface.COREInterface14;
ILogSys log = coreInterface.Log;
// Note flags are necessary to produce Design Automation output. This is same as C++:
// SYSLOG_INFO | SYSLOG_IGNORE_VERBOSITY | SYSLOG_BROADCAST
log.LogEntry(0x00000004 | 0x00040000 | 0x00010000, false, "", string.Format(format, args));
}
}
}