public static int ConvertToTriangleFaces(uint nodeHandle,
bool convertToTri = true, // C# now supports default parameters
bool addShell = true,
float shell = 0.1f,
bool addEditMesh = true,
bool collapseNode = true,
bool centerPivot = true)
{
try
{
IGlobal global = Autodesk.Max.GlobalInterface.Instance;
IInterface14 ip = global.COREInterface14;
IINode node = ip.GetINodeByHandle(nodeHandle);
// Get it's current object state. If a modifier has been applied, for example,
// it is going to return the OS of the mesh in it's current form in the timeline.
IObjectState os = node.ObjectRef.Eval(ip.Time);
// Now grab the object itself.
IObject objOriginal = os.Obj;
// Let's make sure it is a TriObject, which is the typical kind of object with a mesh
if (!objOriginal.IsSubClassOf(global.TriObjectClassID))
{
// If it is NOT, see if we can convert it...
if (convertToTri && objOriginal.CanConvertToType(global.TriObjectClassID) == 1)
objOriginal = objOriginal.ConvertToType(ip.Time, global.TriObjectClassID);
else
return -1;
}
// Now we should be safe to know it is a TriObject and we can cast it as such.
// An exception will be thrown...
ITriObject triOriginal = objOriginal as ITriObject;
// Let's first setup a class ID for the type of objects are are creating.
// New TriObject in this case to hold each face.
IClass_ID cid = global.Class_ID.Create((uint)BuiltInClassIDA.TRIOBJ_CLASS_ID, 0);
IMatrix3 mat = node.GetNodeTM(0, null);
IPoint3 ptOffsetPos = node.ObjOffsetPos;
IQuat quatOffsetRot = node.ObjOffsetRot;
IScaleValue scaleOffsetScale = node.ObjOffsetScale;
// We can grab the faces as a List and iterate them in .NET API.
IMesh mesh = triOriginal.Mesh;
IList<IFace> faces = triOriginal.Mesh.Faces;
int nNumFaces = faces.Count;
if (m_bUsingProgress)
{
m_ctrlProgress.PB_ProgressMaxNum = nNumFaces;
}
ADN_UserBreakCheck checkUserBreak = new ADN_UserBreakCheck();
int count = 0;
foreach (IFace face in faces)
{
if (checkUserBreak.Check() == true)
{
return -1;
}
if (m_bUsingProgress)
{
m_ctrlProgress.PB_ProgressCurrNum = ++count;
}
// Create a new TriObject for each new face.
object objectNewFace = ip.CreateInstance(SClass_ID.Geomobject, cid as IClass_ID);
// Create a new node to hold it in the scene.
IObject objNewFace = (IObject)objectNewFace;
IINode n = global.COREInterface.CreateObjectNode(objNewFace);
// Name it and ensure it is unique...
string newname = "ADN-Sample-Face";
ip.MakeNameUnique(ref newname);
n.Name = newname;
// Based on what we created above, we can safely cast it to TriObject
ITriObject triNewFace = objNewFace as ITriObject;
// Setup the new TriObject with 1 face, and the vertex count from the original object's face we are processing
triNewFace.Mesh.SetNumFaces(1, false, false);
triNewFace.Mesh.SetNumVerts(face.V.Count(), false, false);
// Finish setting up the face (always face '0' because there will only be one per object).
triNewFace.Mesh.Faces[0].SetVerts(0, 1, 2);
triNewFace.Mesh.Faces[0].SetEdgeVisFlags(EdgeVisibility.Vis, EdgeVisibility.Vis, EdgeVisibility.Vis);
triNewFace.Mesh.Faces[0].SmGroup = 2;
// Now, for each vertex, get the old face's points and store into new.
for (int i = 0; i < face.V.Count(); i++)
{
//Get the vertex from the original object's face we are processing
IPoint3 point = triOriginal.Mesh.GetVert((int)face.GetVert(i));
// Set the vertex point in the new face vertex
triNewFace.Mesh.SetVert(i, point);
}
// make it draw.
triNewFace.Mesh.InvalidateGeomCache();
if (addShell)
AddOsmShell(n.Handle, shell);
if (addEditMesh)
AddOsmEditMesh(n.Handle);
if (collapseNode)
ip.CollapseNode(n, true);
// update transform to match object being exploded.
n.SetNodeTM(0, mat);
n.ObjOffsetPos = ptOffsetPos;
n.ObjOffsetRot = quatOffsetRot;
n.ObjOffsetScale = scaleOffsetScale;
n.ObjOffsetPos = ptOffsetPos;
if (centerPivot)
n.CenterPivot(0, false);
}
}
catch (Exception)
{
return -1;
}
return 1;
}