Class FaceClusterList
See Also: Class AdjFaceList, Class BitArray.
class FaceClusterList
Description:
This is a list of face "clusters" for a given mesh. A typical application would be in Edit(able) Mesh, where the user has selected two separate groups of faces on different parts of the mesh and wants to extrude them both, or rotate both around their local centers. Each "cluster" is a contiguous group of selected faces. Like AdjEdgeLists and AdjFaceLists, this class is only defined in relation to some mesh.
This class may be used to group faces together based on the angle between their normals or by their selection status.
All methods of this class are implemented by the system. Note that the functionality provided by this class is not available in the 1.0 release of the SDK. Later releases (1.1, 1.2, etc) do support it.
Data Members:
public:
DWORDTab clust;
The cluster number (id), one for each face. Non-selected faces have UNDEFINED for their id.
The cluster IDs of all the faces -- this table has size mesh::numFaces. clust[i] is UNDEFINED if face i is not in any cluster (ie is unselected).
DWORD count;
The number of clusters.
Methods:
Prototype:
FaceClusterList(Mesh *mesh, AdjFaceList& adj, float angle, BOOL useSel);
Remarks:
Constructor. This version separates clusters using a minimum angle and optionally the selection set. A developer creates one of these cluster lists by specifying the mesh, the face list and an angle. What is built is a cluster number for each face identifying what cluster it is in.
For example, if you create one of these for a sphere and set the angle threshold to 90 degrees, you would get back one cluster, and the cluster id for everything would be 0. If you ran it on a box, and you set the angle to < 90 degrees, you would get back 6 ids. Two faces in the box would have id 0, two would have id 1, etc.
Parameters:
Mesh *mesh
The mesh to create the list for.
AdjFaceList& adj
The face list for this mesh.
float angle
The maximum angle (in radians) that can be used in joining adjacent faces into the same cluster.
BOOL useSel
If FALSE, selection is ignored and all faces are grouped into clusters by angle. If TRUE, only selected faces are grouped into clusters, but angle is still relevant. Non-selected faces will have UNDEFINED for their id.
Prototype:
FaceClusterList(BitArray& fsel, AdjFaceList& adj);
Remarks:
Constructor. This version separates clusters using the selection set. In this case a cluster is defined as a set of faces that are selected and are adjacent. For example you could have a sphere with some faces selected on one side, and another group of faces selected on the other side. Each group of adjacent and selected faces would comprise clusters within the mesh. This is used for example by the axis tripods in 3ds max where each selected group of faces gets their own coordinate system.
In this case the unselected faces will not be in any cluster. These store the value UNDEFINED for their id.
Parameters:
BitArray& fsel
This bit array defines the face selected state that the clusters will be grouped by. Each bit in the bit array corresponds to the parallel index in the mesh face table.
AdjFaceList& adj
The face list for this mesh.
Prototype:
void MakeVertCluster(Mesh &mesh, Tab<DWORD> &vclust);
Remarks:
This method is available in release 3.0 and later only.
Creates a list of cluster IDs for vertices.
Parameters:
Mesh &mesh
The mesh associated with this FaceClusterList.
Tab<DWORD> &vclust
This is where the output goes: vclust is set to size mesh.numVerts, and the value of each entry in this table tells which cluster the vertex has been assigned to, based on the faces it's on. If vertex "v" is not in any clusters (ie none of the faces that use it are in any clusters), vclust[v] is UNDEFINED.
In cases where a vertex is in two clusters, the larger face index is dominant. (In other words, if a vertex 6 is on faces 2 and 7, which are in two separate clusters, and face 9, which isn't in any cluster, it gets its cluster ID from face 7. This can happen if two selection regions touch at a vertex instead of along an edge.)
Prototype:
void GetNormalsCenters(Mesh &mesh, Tab<Point3> &norm, Tab<Point3> &ctr);
Remarks:
This method is available in release 3.0 and later only.
Computes average normals and centers for all face clusters. Within a cluster, normals are weighted by the area of the face -- a face twice as big contributes twice as much to the cluster normal. (Mathematically, we just total up the non-normalized cross-products of each face, which are equivalent to 2*(area)*(face normal). Then we normalize the cluster total.) Face centers are directly averaged, without weighting.
Parameters:
Mesh &mesh
The mesh associated with this FaceClusterList.
Tab<Point3> &norm
The average normal table to store the results in. This is set to size FaceClusterList::count, the number of clusters.
Tab<Point3> &ctr
The average center table to store the results in. This is set to size FaceClusterList::count, the number of clusters.
Prototype:
void GetBorder(DWORD clustID, AdjFaceList &af, Tab<DWORD> &cbord);
Remarks:
This method is available in release 3.0 and later only.
Each face cluster is a set of faces connected by shared edges. This method finds a cluster's boundary, which can be expressed as a sequence of edges on faces in the cluster (where the other side of each edge has no face or has a face not in this cluster). If there is more than one boundary, as for instance in the faces that make up the letter "o" in a ShapeMerge with Text, both boundaries are returned in no particular order.
Parameters:
DWORD clustID
The cluster to get the border of.
AdjFaceList &af
The adjacent face list associated with this FaceClusterList.
Tab<DWORD> &cbord
The table where the output goes. If there are no borders (as for instance in a sphere with all faces selected), it remains empty. Otherwise, this is filled with a series of edge indices, then an UNDEFINED to mark the end of each border. So for instance if this cluster represents the front face of a default box, cbord will contain 4 edge indices and an UNDEFINED. If the cluster represents all the side faces of a cylinder, but not the top or bottom, there are two borders: on 24-sided cylinder, you'd get the 24 edge indices representing the bottom lip of the cylinder, then an UNDEFINED, then the 24 edge indices representing the top lip, followed by another UNDEFINED. (As elsewhere, edges are indexed by face*3+eid, where face is the face (in the cluster) the edge is on, and eid is the index of the edge on that face.)
Prototype:
void GetOutlineVectors(Mesh & m, AdjFaceList &af, Tab<Point3> &cnorms, Tab<Point3> &odir);
Remarks:
This method is available in release 3.0 and later only.
This creates "outline" directions for the vertices on the edge of the clusters. These are used in Edit(able) Mesh's new "Bevel" operation (when you Bevel by "Group"). These vectors, which are all perpendicular to the cluster normals, point in the direction and speed vertices must travel in order to move the edges out at a consistent rate without changing the shape of the outline of the cluster.
To see how this works, create a Prism in 3ds max ("Extended Primitives") with dimensions like 20 x 40 x 40 x 40, and apply an Edit Mesh. Select all the faces on the top of the prism, and spin the Bevel spinner up and down. Notice that the vertex at the sharpest point moves faster than the other 2, but that the edges all remain parallel to their original positions. The essence of Outlining is that the edges move at a constant rate, and the vertices move faster or slower to make this happen. (This strategy is also used in the Bevel and Path Bevel modifiers.)
Parameters:
Mesh & m
The mesh associated with this FaceClusterList
AdjFaceList &af
The adjacent face list associated with this FaceClusterList
Tab<Point3> &cnorms
The cluster normals, as computed by GetNormalsCenters
Tab<Point3> &odir
A table to put the outline direction result in. This is set to size mesh.numVerts. Entries for vertices that are not on a cluster border are all (0,0,0). Entries for cluster border vertices are scaled, such that if you move all vertices the specified amount, each cluster's border edges will move by one 3ds max unit.
Operators:
Prototype:
DWORD operator[](int i)
Remarks:
Access operator. Returns the cluster ID for face i.