meshMapUtils.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

// 
// meshMapUtils.cpp
// 
// Description:
//    Utility functions for the meshRemap and meshReorder commands
//       moveToolContext
// 

#include <assert.h>

#include "meshMapUtils.h"

#include <maya/MIntArray.h>
#include <maya/MFnMesh.h>
#include <maya/MItMeshEdge.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MGlobal.h>
#include <maya/MFloatPointArray.h>
#include <maya/MDagPath.h>
#include <maya/MDagPathArray.h>
#include <maya/MObjectArray.h>
#include <maya/MItMeshVertex.h>


//
// Modulating index, will return 0..l-1, for any integer value
#define IDX(i, l) ( ( i + l ) % l )

//
// Intersect the current face list with the one provided, keep only the common elements
// 
void meshMapUtils::intersectArrays( MIntArray& selection, MIntArray& moreFaces )
{
        int j = selection.length() - 1;
        while ( j >= 0 )
        {
                bool found = false;;

                // For each item in moreFaces, try find it in fSelectedFaces
                for( unsigned int i = 0 ; i < moreFaces.length(); i++ )
                {
                        if( selection[j] == moreFaces[i] )
                        {
                                found = true;
                                break;
                        }
                }       

                if( !found )
                {
                        selection.remove(j);
                }

                j--;
        }
}


//
//  Recursively traverse a mesh by processing each face, and the neighbouring faces along it's edges.
//  The initial invocation of this routine provides the basis for the new first vertex/edge
//  and faces.  
//
//  The result of this routine is an array of values that map the old CV indices to the new ones. Along
//  the a new list of reindexed CVs is built, along with a list of poly counts and connetions. These
//  can be used to build a new mesh with the reordering specfied by the seed face and vertices.
//
//
//  Inputs: 
//              path                            : Path to the object being traversed
//              faceIdx                         : Current face being traversed
//              v0, v1                          : Veretices that define the direction of travel along the face
//              faceTraversal           : An array booleans to track which faces have been 
//                                                      : traversed, controls the recursion  
//              origVertices            : The vertices from the original mesh. The could be obtained
//                                                      : from the path, but are passed in for efficiency
//
//      Outputs:
//              cvMapping                       : Mapping of the existing vertices to their new indices
//                                                      : the fist values in the final array will be the intial v0, v1
//              cvMappingInverse        : The inverse of the cvMapping
//                                                      : the value of items v0 and v1 will be 0 and 1 respectively
//              newPolygonCounts        : Vertex counts for each of the new faces
//              newPolygonConnects  : Connections, specified in terms of new CV indices
//              newVertices                     : The orginal vertices resorted based on the reindexing
//
//
MStatus meshMapUtils::traverseFace( 
        MDagPath&       path,
        int faceIdx, 
        int v0, 
        int v1, 
        MIntArray& faceTraversal,
        MIntArray& cvMapping,
        MIntArray& cvMappingInverse,
        MIntArray& newPolygonCounts,
        MIntArray& newPolygonConnects,
        MFloatPointArray& origVertices,
        MFloatPointArray& newVertices
)
{
        int vtxCnt = -1;
        int dir = 0;
        int dummy;              // For setIndex calls

        MStatus stat = MStatus::kSuccess;

        MFnMesh theMesh( path, &stat );
        MItMeshPolygon polyIt( path );
        MItMeshEdge edgeIt( path );

        if( stat != MStatus::kSuccess )
        {
                MGlobal::displayError( " theMesh.getPoint failed");
                return stat;
        }


        //
        // Skip over any faces already processed, this is not a failure
        // 
        if( faceTraversal[faceIdx] )
        {
                return MStatus::kSuccess;
        }

        //
        // get the vertex/edge information and sort it based on the user seed
        //
        MIntArray vtxOrig;
        MIntArray edgeOrig;

        polyIt.setIndex( faceIdx, dummy );
        polyIt.getEdges( edgeOrig );       
        polyIt.getVertices( vtxOrig );     

        vtxCnt = vtxOrig.length();

        // 
        // the sorted V/E info
        // 
        MIntArray vtxSorted( vtxCnt );
        MIntArray edgeSorted( vtxCnt );

        //
        // Build a new array ordered with v0, then v1, first figure out the 
        // starting point, and direction 
        //
        int v0Idx =     -1;
        int i;
        for( i = 0; i < vtxCnt; i++ )
        {
                if( vtxOrig[i] == v0 )
                {
                        // We've found v0, now find in what direction we need to travel to find v1
                                        
                        v0Idx = i;
                        
                        if( vtxOrig[IDX(i+1, vtxCnt)] == v1 )
                        {
                                dir = 1;
                        }
                        else if( vtxOrig[IDX(i-1, vtxCnt)] == v1 )
                        {
                                dir = -1;
                        }
                        else
                        {
                                assert( dir != 0 );
                        }       
                        break;
                }
        }

        // Now sort the vertex/edge arrays
        for( i = 0; i < vtxCnt; i++ )
        {
                vtxSorted[i] = vtxOrig[IDX( v0Idx + i * dir, vtxCnt )];
                if( dir == 1 )
                {
                        edgeSorted[i] = edgeOrig[IDX( v0Idx + i * dir, vtxCnt )];
                }
                else
                {
                        edgeSorted[i] = edgeOrig[IDX( v0Idx - 1 + i * dir, vtxCnt )];
                }
        }


        // Add any new CVs to the vertex array being constructed
        for ( i = 0; i < vtxCnt; i++ )
        {
                MPoint pos;
                int index = vtxSorted[i];

                if( cvMapping[index] == -1  )
                {
                        if( stat != MStatus::kSuccess )
                        {
                                MGlobal::displayError( " theMesh.getPoint failed");
                                return stat;
                        }

                        // Added the new CV, and mark it as transferred
                        newVertices.append( origVertices[index] );

                        // Store the mapping from the old CV indices to the new ones
                        cvMapping[index] = newVertices.length()-1;
                        cvMappingInverse[newVertices.length()-1] = index;
                }

        }

        //
        //  Add the new face count 
        //
        newPolygonCounts.append( vtxCnt );

        //
        //  Add the new polyConnects
        
        for ( i = 0; i < vtxCnt; i++ )
        {
                newPolygonConnects.append( cvMapping[vtxSorted[i]] );
        }

        // Mark this face as complete 
        faceTraversal[faceIdx] = true;

        //
        //  Now recurse over the edges of this face
        // 
        for( i = 0; i < (int)edgeSorted.length(); i++ )
        {
                int nextEdge = edgeSorted[i];

                int2 nextEdgeVtx;
                stat = theMesh.getEdgeVertices(nextEdge, nextEdgeVtx );

                //
                // Find the vertex, in the sorted array, that starts the next edge
                int baseIdx = -1;
                bool swap = false;
                int j;
                for( j = 0; j < (int)vtxSorted.length(); j++ )
                {
                        if( vtxSorted[j] == nextEdgeVtx[0] )
                        {
                                baseIdx = j;
                                break;
                        }
                }

                assert( baseIdx != -1 );
        
                // 
                // Now look forward and backward in the vertex array to find the
                // edge's other point, this indicates the edges direction. This
                // is needed to guide the next recursion level, and keep the
                // normals pointed consistenly
                //
                if( vtxSorted[IDX(j+1, vtxCnt)] == nextEdgeVtx[1] )
                {
                        // Nothing
                }
                else if ( vtxSorted[IDX(j-1, vtxCnt)] == nextEdgeVtx[1] )
                {
                        swap = true;
                }


                MIntArray connectedFaces;
                edgeIt.setIndex( nextEdge, dummy );
                edgeIt.getConnectedFaces( connectedFaces );

                // A single face is simply the current one. Recurse over the others
                if( connectedFaces.length() > 1 )
                {
                        int nextFace;
                        if( connectedFaces[0] == faceIdx )
                        {
                                nextFace = connectedFaces[1];
                        }
                        else
                        {
                                nextFace = connectedFaces[0];
                        }

                        int nextVtx0 = -1;
                        int nextVtx1 = -1;
                        if ( !swap )
                        {
                                nextVtx0 = nextEdgeVtx[1];
                                nextVtx1 = nextEdgeVtx[0];
                        }
                        else
                        {
                                nextVtx0 = nextEdgeVtx[0];
                                nextVtx1 = nextEdgeVtx[1];
                        }

                        stat = traverseFace( path, nextFace, nextVtx0, nextVtx1, faceTraversal,
                                        cvMapping, cvMappingInverse, 
                                        newPolygonCounts, newPolygonConnects, 
                                        origVertices, newVertices );

                        // Break out of edge loop on error
                        if( stat != MStatus::kSuccess )
                        {
                                break;
                        }       
                }
        }

        return stat;
}

//
//  Given a list of 3 paths and compoents find the face they define and store their indices
//
MStatus meshMapUtils::validateFaceSelection( MDagPathArray& paths, MObjectArray& components, int *faceIdx, MIntArray *seedVtx )
{
        MStatus stat = MStatus::kSuccess;
        MIntArray finalFaceList;

        if ( paths.length() != 3 && components.length() != 3 )
        {
                return MStatus::kFailure;
        }

        seedVtx->clear();

        for (unsigned int i = 0; i < 3; i++)
        {
                MItMeshVertex fIt ( paths[i], components[i], &stat );
                if( stat != MStatus::kSuccess || fIt.isDone() )
                {
                        MGlobal::displayError( " MItMeshVertex failed");
                        return MStatus::kFailure;
                }

                seedVtx->append( fIt.index() ); // The  cv's location

                MIntArray  faceList;
                stat = fIt.getConnectedFaces ( faceList );
                if( stat != MStatus::kSuccess )
                {
                        MGlobal::displayError( " getConnectedFaces failed");
                        return MStatus::kFailure;
                }

                if( i == 0 )
                {
                        finalFaceList = faceList;
                }
                else
                {
                        meshMapUtils::intersectArrays( finalFaceList, faceList );
                }
        }

        if( finalFaceList.length() != 1 )
        {
                return MStatus::kFailure;
        }
        else
        {
                *faceIdx = finalFaceList[0];
        }

        MDagPath p0( paths[0] );
        MDagPath p1( paths[1] );
        MDagPath p2( paths[2] );

        if( !(p0 == p1 ) || !(p0 == p2 ))
        {
                return MStatus::kFailure;
        }

        return MStatus::kSuccess;
}

Autodesk® Maya® 2009 © 1997-2008 Autodesk, Inc. All rights reserved. Generated with doxygen 1.5.6