/**@file rotatePolyCmd.cpp
@note select a polygon and type in mel -- rotatePolyCmd -r 90; which will rotate in x all vertices by 90 degrees
@author Nathaniel O. Anozie (ogbonnawork at gmail dot com)
@note Modify at your own risk
@note date created: 02/19/2013
@note this has some useful info for undo, user argument, using rotation matrices
@note inspired by Foley & Van Dam Chapter 5, Geometrical Transformations
@note inspired by Rick Parent (cse dot ohio-state dot edu) accessVertices.cpp
@note inspired by Autdodesk Api tutorial examples surfaceTwistCmd.cpp, translateCmd.cpp learning about MMatrix, and MItMeshVertex
*/
//07-07-13 ---- fixed bug so it rotates all vertices, added user argument option, added undo
#include <maya/MGlobal.h>
//im guessing these are needed almost always
//printing stuff, selecting stuff
#include <maya/MItSelectionList.h>
#include <maya/MSelectionList.h>
//need iterating for polygon vertex
#include <maya/MItMeshVertex.h>
//need finding outliner polys
#include <maya/MDagpath.h>
//need for matrix stuff
#include <math.h>
#include <maya/MPoint.h>
#include <maya/MMatrix.h>
//for using arguments hence command
#include <maya/MPxCommand.h>
#include <maya/MFnPlugin.h>
#include <maya/MSyntax.h>
#include <maya/MArgList.h>
#include <maya/MArgDatabase.h>
static const char* g_rFlag = "-r";
static const char* g_rFlagLong = "-rotate";
//for undo
#define DOIT 0
#define UNDOIT 1
static double pi = 3.14159265359;
//if using user arguments
class rotatePolyCmd: public MPxCommand{
public:
rotatePolyCmd(); //needed because we need to initialize data
virtual ~rotatePolyCmd();
virtual bool isUndoable() const;
MStatus doIt( const MArgList& args );
MStatus undoIt();
static void* creator();
//for syntax
static MSyntax newSyntax();
private:
//any other functions
MStatus action( int flag );
double deg;
};
rotatePolyCmd::rotatePolyCmd()
{
deg = 90;
}
rotatePolyCmd::~rotatePolyCmd(){}
void* rotatePolyCmd::creator(){return new rotatePolyCmd;}
bool rotatePolyCmd::isUndoable() const{ return true; }
MSyntax rotatePolyCmd::newSyntax()
{
MSyntax syntax;
//add flag
syntax.addFlag(g_rFlag, g_rFlagLong, MSyntax::kDouble);
return syntax;
}
//last stuff
MStatus initializePlugin( MObject obj)
{
MStatus stat;
MFnPlugin fnPlugin( obj, "Nathaniel Anozie", "1.0", "Any");
//need user argument function and creator
stat = fnPlugin.registerCommand("rotatePolyCmd",rotatePolyCmd::creator, rotatePolyCmd::newSyntax);
if(stat != MS::kSuccess){stat.perror("could not register !!!");};
return stat;
}
MStatus uninitializePlugin(MObject obj)
{
MStatus stat;
MFnPlugin fnPlugin(obj);
stat = fnPlugin.deregisterCommand("rotatePolyCmd");
if(stat != MS::kSuccess){stat.perror("could not de-register !!!");};
return stat;
}
////
/**the names here needs to match that used in our command or DeclareSimpleCommand
@note notice no dollar signs, also we
@note need to do search manual to figure out the kind of thing that will help us find keyframes
@note the ampersand is alot different from MEL cause in MEL
@note i think only arrays are passed by reference
@note here a boolean type thing can be edited somewhere else and we can see what we got for error checking
*/
MStatus rotatePolyCmd::doIt( const MArgList& args )
{
MStatus stat = MS::kSuccess; //we want this for error checking
double degree = 90; //default degrees to rotate
//---------- constants
//rotate in x all polys of all selected polys about origin
//create parser for user arguments
MArgDatabase argData(syntax(), args, &stat);
if(stat != MS::kSuccess)
{
stat.perror("arguments not correct !!!");
return stat;
}
//get user argument
if(argData.isFlagSet(g_rFlag))
argData.getFlagArgument(g_rFlag, 0, degree );
deg = degree;
return action( DOIT );//give back success of a different function
}
MStatus rotatePolyCmd::undoIt( )
{
return action( UNDOIT );
}
//flag -- DOIT or UNDOIT
//deg DEGREES to rotate
MStatus rotatePolyCmd::action( int flag )
{
MStatus stat;
//figure out rotation amount for undo it will be negative of the do
double degree = deg;
switch( flag )
{
case UNDOIT:
degree = -degree;
case DOIT:
break;
default:
break;
}
double rotAmt = (pi/180) * degree; //in radians
MSelectionList selList;
MGlobal::getActiveSelectionList(selList);
if(selList.length() != 1){
MGlobal::displayError("Requires a Polygon Selected !!!\n");
return MS::kFailure;
}
//not yet any restrictions
MItSelectionList polyIt(selList, MFn::kMesh, &stat);//instead of setFilter
//if used MFn::kInvalid i think more items possible. for any kind poly,nurbs, ..
if(MS::kSuccess == stat){
MDagPath meshDag;
MObject mComponent; //will hold current vtx
//loop polys, were not looping vertices yet
for( ; !polyIt.isDone(); polyIt.next() )
{
polyIt.getDagPath(meshDag, mComponent); //saves how to find this poly from outliner
MItMeshVertex vtxIter( meshDag, mComponent, &stat);
if( MS::kSuccess == stat ){
//How we should rotate is fixed for all vertices
//This is counter clockwise rotation about --- X --- axis
double rotation = rotAmt;
MMatrix rMatrix;
rMatrix(0,0) = 1;
rMatrix(0,1) = 0;
rMatrix(0,2) = 0;
rMatrix(1,0) = 0;
rMatrix(1,1) = cos( rotation );
rMatrix(1,2) = sin( rotation );
rMatrix(2,0) = 0;
rMatrix(2,1) = -sin( rotation );
rMatrix(2,2) = cos( rotation );
//rotate vertices
for( ; !vtxIter.isDone(); vtxIter.next() ){
MPoint pnt = vtxIter.position( MSpace::kWorld); //MSpace::kWorld
MPoint newPnt;
//rotate computation
newPnt = ( rMatrix * pnt );
stat = vtxIter.setPosition( newPnt, MSpace::kWorld);
if( MS::kSuccess != stat ){
cerr << "Error setting Vertex\n -- Exiting";
break;
}
}//end vertex loop
}
}//end poly loop
}
return MS::kSuccess;
}