//+ // ============================================================================ // Copyright (C) Alias Systems Corp., and/or its licensors ("Alias"). // All rights reserved. These coded instructions, statements, computer // programs, and/or related material (collectively, the "Material") // contain unpublished information proprietary to Alias, which is // protected by Canadian and US federal copyright law and by international // treaties. This Material may not be disclosed to third parties, or be copied // or duplicated, in whole or in part, without the prior written consent of // Alias. ALIAS HEREBY DISCLAIMS ALL WARRANTIES RELATING TO THE MATERIAL, // INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR IMPLIED WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. // IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES WHATSOEVER, WHETHER DIRECT, // INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, OR IN EQUITY, ARISING OUT OF OR RELATED TO THE // ACCESS TO, USE OF, OR RELIANCE UPON THE MATERIAL. // ============================================================================ //- //////////////////////////////////////////////////////////////////////// // // meshMapUtils.cpp // // Description: // Utility functions for the meshRemap and meshReorder commands // moveToolContext // //////////////////////////////////////////////////////////////////////// #include #include "meshMapUtils.h" #include #include #include #include #include #include #include #include #include #include // // 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++ ) { MStatus stat; 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; }