meshRemapTool.cpp
#define _MApiVersion
#include <maya/MIOStream.h>
#include <maya/MGlobal.h>
#include <maya/MCursor.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MItMeshVertex.h>
#include <maya/MFnMesh.h>
#include <maya/MPointArray.h>
#include <maya/MVector.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MMatrix.h>
#include <meshRemapTool.h>
#include <meshMapUtils.h>
const double epsilon = 0.00001;
meshRemapTool::meshRemapTool()
{
setTitleString ( "Mesh Remap Tool" );
setCursor( MCursor::editCursor );
reset();
}
meshRemapTool::~meshRemapTool() {}
void* meshRemapTool::creator()
{
return new meshRemapTool;
}
void meshRemapTool::toolOnSetup ( MEvent & )
{
reset();
}
void meshRemapTool::reset()
{
fNumSelectedPoints = 0;
fSelectedPathSrc.clear();
fSelectedComponentSrc.clear();
fSelectVtxSrc.clear();
fSelectedFaceSrc = -1;
fSelectedPathDst.clear();
fSelectedComponentDst.clear();
fSelectVtxDst.clear();
fSelectedFaceDst = -1;
fCurrentHelpString = "Select 1st point on source mesh.";
helpStateHasChanged();
}
MStatus meshRemapTool::doRelease( MEvent & event )
{
char buf[1024];
MStatus stat = MPxSelectionContext::doRelease(event);
MGlobal::getActiveSelectionList( fSelectionList );
MObject component;
MDagPath path;
MItSelectionList selectionIt (fSelectionList, MFn::kComponent);
MStringArray selections;
selectionIt.getStrings( selections );
if( selections.length() == 0 )
{
if( fNumSelectedPoints == 0 || fNumSelectedPoints == 3 )
{
MItSelectionList selectionDag (fSelectionList, MFn::kDagNode);
if (!selectionDag.isDone() && selectionDag.getDagPath(path) == MS::kSuccess)
{
path.extendToShape();
if (path.hasFn(MFn::kMesh))
{
selectionDag.next();
if (selectionDag.isDone())
{
return MS::kSuccess;
}
}
}
}
if( fNumSelectedPoints == 0 )
{
MItSelectionList selectionDag (fSelectionList, MFn::kDagNode);
if (!selectionDag.isDone() && selectionDag.getDagPath(path) == MS::kSuccess)
{
path.extendToShape();
if (path.hasFn(MFn::kMesh))
{
selectionDag.next();
if (!selectionDag.isDone() &&
selectionDag.getDagPath(path) == MS::kSuccess)
{
path.extendToShape();
if (path.hasFn(MFn::kMesh))
{
selectionDag.next();
if (selectionDag.isDone())
{
return MS::kSuccess;
}
}
}
}
}
}
}
if( selections.length() != 1 )
{
MGlobal::displayError( "Must select exactly one vertex" );
return MS::kSuccess;
}
if (selectionIt.isDone ())
{
MGlobal::displayError( "Selected item not a vertex" );
return MS::kSuccess;
}
if( selectionIt.getDagPath (path, component) != MStatus::kSuccess )
{
MGlobal::displayError( "Must select a mesh or its vertex" );
return MS::kSuccess;
}
if (!path.node().hasFn(MFn::kMesh) && !(path.node().hasFn(MFn::kTransform) && path.hasFn(MFn::kMesh)))
{
MGlobal::displayError( "Must select a mesh or its transform" );
return MS::kSuccess;
}
MItMeshVertex fIt ( path, component, &stat );
if( stat != MStatus::kSuccess )
{
MGlobal::displayError( "MItMeshVertex failed");
return MStatus::kFailure;
}
if (fIt.count() != 1 )
{
sprintf(buf, "Invalid selection '%s'. Vertices must be picked one at a time.", selections[0].asChar() );
MGlobal::displayError( buf );
return MS::kSuccess;
}
else
{
sprintf(buf, "Accepting vertex '%s'", selections[0].asChar() );
MGlobal::displayInfo( buf );
}
if( fNumSelectedPoints < 3 )
{
fSelectedPathSrc.append( path );
fSelectedComponentSrc.append( component );
}
else
{
fSelectedPathDst.append( path );
fSelectedComponentDst.append( component );
}
if( fNumSelectedPoints == 2 )
{
if( ( stat = meshMapUtils::validateFaceSelection( fSelectedPathSrc, fSelectedComponentSrc, &fSelectedFaceSrc, &fSelectVtxSrc ) ) != MStatus::kSuccess )
{
MGlobal::displayError("Selected vertices don't define a unique face on source mesh");
reset();
return stat;
}
}
if( fNumSelectedPoints == 5 )
{
if( ( stat = meshMapUtils::validateFaceSelection( fSelectedPathDst, fSelectedComponentDst, &fSelectedFaceDst, &fSelectVtxDst ) ) != MStatus::kSuccess )
{
MGlobal::displayError("Selected vertices don't define a unique face on destination mesh");
reset();
return stat;
}
executeCmd();
}
else
{
fNumSelectedPoints++;
}
helpStateHasChanged();
return stat;
}
MStatus meshRemapTool::resolveMapping()
{
MGlobal::getActiveSelectionList( fSelectionList );
if( fSelectionList.length() != 2)
{
reset();
helpStateHasChanged();
return MStatus::kFailure;
}
MDagPath dagPath;
MObject component;
if( fSelectionList.getDagPath(0, dagPath, component) != MStatus::kSuccess)
{
MGlobal::displayError(" Invalid source mesh");
return MStatus::kFailure;
}
dagPath.extendToShape();
fSelectedPathSrc.append(dagPath);
fSelectedPathSrc.append(dagPath);
fSelectedPathSrc.append(dagPath);
if( fSelectionList.getDagPath(1, dagPath, component) != MStatus::kSuccess)
{
MGlobal::displayError(" Invalid destination mesh");
return MStatus::kFailure;
}
dagPath.extendToShape();
fSelectedPathDst.append(dagPath);
fSelectedPathDst.append(dagPath);
fSelectedPathDst.append(dagPath);
MPointArray srcPts;
MIntArray srcVertIds, dstVertIds;
MItMeshPolygon faceIterSrc(fSelectedPathSrc[0]);
unsigned srcFaceId = faceIterSrc.index();
faceIterSrc.getPoints(srcPts, MSpace::kObject);
faceIterSrc.getVertices(srcVertIds);
unsigned i, j;
MMatrix m = fSelectedPathDst[0].inclusiveMatrix();
for(i = 0; i < srcPts.length(); i++)
{
srcPts[i] = srcPts[i] * m;
}
MItMeshPolygon faceIterDst(fSelectedPathDst[0]);
while (!faceIterDst.isDone())
{
MPointArray dstPts;
faceIterDst.getPoints(dstPts, MSpace::kWorld);
if (arePointsOverlap(srcPts, dstPts))
{
fSelectedFaceSrc = srcFaceId;
fSelectedFaceDst = faceIterDst.index();
fSelectVtxSrc.append(srcVertIds[0]);
fSelectVtxSrc.append(srcVertIds[1]);
fSelectVtxSrc.append(srcVertIds[2]);
faceIterDst.getVertices(dstVertIds);
for (j = 0; j < dstPts.length(); j++)
{
MVector v = dstPts[j] - srcPts[0];
if (v * v < epsilon)
{
fSelectVtxDst.append(dstVertIds[j]);
break;
}
}
for (j = 0; j < dstPts.length(); j++)
{
MVector v = dstPts[j] - srcPts[1];
if (v * v < epsilon)
{
fSelectVtxDst.append(dstVertIds[j]);
break;
}
}
for (j = 0; j < dstPts.length(); j++)
{
MVector v = dstPts[j] - srcPts[2];
if (v * v < epsilon)
{
fSelectVtxDst.append(dstVertIds[j]);
break;
}
}
return MStatus::kSuccess;
}
faceIterDst.next();
}
return MStatus::kFailure;
}
bool meshRemapTool::arePointsOverlap(const MPointArray& srcPts, const MPointArray& dstPts) const
{
unsigned i, j;
for(i = 0; i < 3; i++)
{
bool overlap = false;
const MPoint &pt = srcPts[i];
for(j = 0; j < dstPts.length(); j++)
{
MVector v = dstPts[j] - pt;
if (v * v < epsilon)
{
overlap = true;
break;
}
}
if (!overlap) return false;
}
return true;
}
void meshRemapTool::completeAction()
{
if( resolveMapping() != MStatus::kSuccess )
{
reset();
return;
}
executeCmd();
}
void meshRemapTool::executeCmd()
{
char cmdString[200];
sprintf(cmdString, "meshRemap %s.vtx[%d] %s.vtx[%d] %s.vtx[%d] %s.vtx[%d] %s.vtx[%d] %s.vtx[%d]",
fSelectedPathSrc[0].partialPathName().asChar(), fSelectVtxSrc[0],
fSelectedPathSrc[1].partialPathName().asChar(), fSelectVtxSrc[1],
fSelectedPathSrc[2].partialPathName().asChar(), fSelectVtxSrc[2],
fSelectedPathDst[0].partialPathName().asChar(), fSelectVtxDst[0],
fSelectedPathDst[1].partialPathName().asChar(), fSelectVtxDst[1],
fSelectedPathDst[2].partialPathName().asChar(), fSelectVtxDst[2]);
MGlobal::executeCommand(cmdString, true, true);
MGlobal::clearSelectionList();
MGlobal::displayInfo( "Mesh remapping complete" );
reset();
}
void meshRemapTool::helpStateHasChanged()
{
switch (fNumSelectedPoints)
{
case 0:
fCurrentHelpString = "For auto remap select source mesh and then destination mesh and Press Enter. For manual remap select 1st vertex on source mesh.";
break;
case 1:
fCurrentHelpString = "Select 2nd vertex on source mesh.";
break;
case 2:
fCurrentHelpString = "Select 3rd vertex on source mesh.";
break;
case 3:
fCurrentHelpString = "Select 1st vertex on target mesh.";
break;
case 4:
fCurrentHelpString = "Select 2nd vertex on target mesh.";
break;
case 5:
fCurrentHelpString = "Select 3rd vertex on target mesh.";
break;
default:
break;
}
setHelpString( fCurrentHelpString );
}
MPxContext* meshRemapContextCmd::makeObj()
{
return new meshRemapTool;
}
void* meshRemapContextCmd::creator()
{
return new meshRemapContextCmd;
}