- Main Page
- Related Pages
- Modules
- Classes
- Examples

# pointOnMeshCmd.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.
    // ==========================================================================
    //+

    // DISCLAIMER: THIS PLUGIN IS PROVIDED AS IS.  IT IS NOT SUPPORTED BY

    //            AUTODESK, SO PLEASE USE AND MODIFY AT YOUR OWN RISK.

    //

    // PLUGIN NAME: pointOnMeshInfo v1.0

    // FILE: pointOnMeshCmd.cpp

    // DESCRIPTION: -Defines `pointOnMesh` MEL command.

    //              -Please see readme.txt for full details.

    // AUTHOR: QT

    // REFERENCES: -This plugin is based off of the `pointOnSurface` MEL command and "pointOnSurfaceInfo" node.

    //             -The pointOnSubdNode.cpp plugin example from the Maya API Devkit was also used for reference.

    //             -The MEL script AEpointOnSurfaceInfoTemplate.mel was referred to for the AE template MEL script

    //              that accompanies the pointOnMeshInfo node.

    // LAST UPDATED: Oct. 11th, 2001.

    // COMPILED AND TESTED ON: Maya 4.0 on Windows

    // HEADER FILES:

    #include "pointOnMeshCmd.h"

    #include "getPointAndNormal.h"

    // CONSTRUCTOR DEFINITION:

    pointOnMeshCommand::pointOnMeshCommand()

    {

    }

    // DESTRUCTOR DEFINITION:

    pointOnMeshCommand::~pointOnMeshCommand()

    {

    }

    // METHOD FOR CREATING AN INSTANCE OF THIS COMMAND:

    void* pointOnMeshCommand::creator()

    {

       return new pointOnMeshCommand;

    }

    // MAKE THIS COMMAND UNDOABLE:

    bool pointOnMeshCommand::isUndoable() const

    {

       return true;

    }

    // FIRST INVOKED WHEN COMMAND IS CALLED, PARSING THE COMMAND ARGUMENTS, INITIALIZING DEFAULT PARAMETERS, THEN CALLING redoIt():

    MStatus pointOnMeshCommand::doIt(const MArgList& args)

    {

       // INITIALIZE PRIVATE DATA FOR THE COMMAND:

       nodeCreated = positionSpecified = normalSpecified = faceIndexSpecified = relativeSpecified = parameterUSpecified = parameterVSpecified = false;

       meshNodeName = pointOnMeshInfoName = "";

       // PARSE THE COMMAND'S ARGUMENTS:

       for (unsigned i=0; i<args.length(); i++)

       {

          if ((MString("-name")==args.asString(i)) || (MString("-na")==args.asString(i)))

             pointOnMeshInfoName = args.asString(++i);

          else if ((MString("-position")==args.asString(i)) || (MString("-p")==args.asString(i)))

             positionSpecified = true;

          else if ((MString("-normal")==args.asString(i)) || (MString("-nr")==args.asString(i)))

             normalSpecified = true;

          else if ((MString("-faceIndex")==args.asString(i)) || (MString("-f")==args.asString(i)))

          {

             faceIndexSpecified = true;

             int temp = args.asInt(++i);

             if (temp<0)

             {

                displayError("Invalid faceIndex!");

                return MS::kFailure;

             }

             faceIndex = temp;

          }

          else if ((MString("-relative")==args.asString(i)) || (MString("-r")==args.asString(i)))

          {

             relativeSpecified = true;

             relative = args.asBool(++i);

          }

          else if ((MString("-parameterU")==args.asString(i)) || (MString("-u")==args.asString(i)))

          {

             parameterUSpecified = true;

             double temp = args.asDouble(++i);

             if ((temp<0) || (temp>1))

             {

                displayError("Invalid parameterU!");

                return MS::kFailure;

             }

             parameterU = temp;

          }

          else if ((MString("-parameterV")==args.asString(i)) || (MString("-v")==args.asString(i)))

          {

             parameterVSpecified = true;

             double temp = args.asDouble(++i);

             if ((temp<0) || (temp>1))

             {

                displayError("Invalid parameterV!");

                return MS::kFailure;

             }

             parameterV = temp;

          }

          else if (i==(args.length()-1))

             meshNodeName = args.asString(i);

          else

          {

             MString errorMessage = "Invalid flag: ";

             errorMessage += args.asString(i);

             displayError(errorMessage);

             return MS::kFailure;

          }

       }

       // MAKE SURE UNSPECIFIED INPUT PARAMETER FLAGS GET DEFAULT VALUES:

       if (!faceIndexSpecified)

          faceIndex = 0;

       if (!relativeSpecified)

          relative = true;

       if (!parameterUSpecified)

          parameterU = 0.5;

       if (!parameterVSpecified)

          parameterV = 0.5;

       // DO THE WORK:

       return redoIt();

    }

    // DOES MOST OF THE WORK IN COMPUTING THE POSITION, NORMAL, OR CREATING A "pointOnMeshInfo" NODE:

    MStatus pointOnMeshCommand::redoIt()

    {

       // WHEN NO MESH IS SPECIFIED IN THE COMMAND, GET THE FIRST SELECTED MESH FROM THE SELECTION LIST:

       MSelectionList sList;

       if (meshNodeName=="")

       {

          MGlobal::getActiveSelectionList(sList);

          if (sList.length()==0)

          {

             displayError("No mesh or mesh transform specified!");

             return MS::kFailure;

          }

       }

       // OTHERWISE, USE THE NODE NAME SPECIFIED IN THE LAST ARGUMENT OF THE COMMAND:

       else if (sList.add(meshNodeName) == MS::kInvalidParameter)

       {

          displayError("Specified mesh does not exist!");

          return MS::kFailure;

       }

       // RETRIEVE THE FIRST ITEM FROM THE SELECTION LIST:

       MDagPath meshDagPath;

       sList.getDagPath(0, meshDagPath);

       // CREATE AND CONNECT A "pointOnMeshInfo" NODE, OR GET THE POINT AND NORMAL ACCORDING TO

       // WHETHER THE "-position/-p" AND/OR "-normal/-nr" FLAGS WERE SPECIFIED, AND WHETHER THE MESH

       // "SHAPE" OR ITS "TRANSFORM" WAS SPECIFIED/SELECTED:

       MPoint point;

       MVector normal;

       // WHEN THE SPECIFIED NODE IS THE MESH "SHAPE":

       if (meshDagPath.node().hasFn(MFn::kMesh))

       {

          // WHEN NEITHER "-position/-p" NOR "-normal/-nr" ARE SPECIFIED, CREATE AND CONNECT A "pointOnMeshInfo" NODE AND RETURN ITS NODE NAME:

          if (!positionSpecified && !normalSpecified)

          {

             // CREATE THE NODE:

             nodeCreated = true;

             MFnDependencyNode depNodeFn;

             if (pointOnMeshInfoName == "")

                depNodeFn.create("pointOnMeshInfo");

             else

                depNodeFn.create("pointOnMeshInfo", pointOnMeshInfoName);

             pointOnMeshInfoName = depNodeFn.name();

             // SET THE ".faceIndex" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (faceIndexSpecified)

             {

                MPlug faceIndexPlug = depNodeFn.findPlug("faceIndex");

                faceIndexPlug.setValue(faceIndex);

             }

             // SET THE ".relative" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (relativeSpecified)

             {

                MPlug relativePlug = depNodeFn.findPlug("relative");

                relativePlug.setValue(relative);

             }

             // SET THE ".parameterU" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (parameterUSpecified)

             {

                MPlug parameterUPlug = depNodeFn.findPlug("parameterU");

                parameterUPlug.setValue(parameterU);

             }

             // SET THE ".parameterV" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (parameterVSpecified)

             {

                MPlug parameterVPlug = depNodeFn.findPlug("parameterV");

                parameterVPlug.setValue(parameterV);

             }

             // CONNECT THE NODES:

             MPlug worldMeshPlug, inMeshPlug;

             inMeshPlug = depNodeFn.findPlug("inMesh");

             depNodeFn.setObject(meshDagPath.node());

             worldMeshPlug = depNodeFn.findPlug("worldMesh");

             worldMeshPlug = worldMeshPlug.elementByLogicalIndex(0);  // ASSUME THE *FIRST* INSTANCE OF THE MESH IS REQUESTED FOR MESH SHAPES.

             MDGModifier dgModifier;

             dgModifier.connect(worldMeshPlug, inMeshPlug);

             dgModifier.doIt();

             // SET COMMAND RESULT AND RETURN:

             setResult(pointOnMeshInfoName);

             return MStatus::kSuccess;

          }

          // OTHERWISE, COMPUTE THE POINT-POSITION AND NORMAL, USING THE *FIRST* INSTANCE'S TRANSFORM:

          else

             getPointAndNormal(meshDagPath, faceIndex, relative, parameterU, parameterV, point, normal);

       }

       // WHEN THE SPECIFIED NODE IS A "TRANSFORM" OF A MESH SHAPE:

       else if (meshDagPath.node().hasFn(MFn::kTransform) && meshDagPath.hasFn(MFn::kMesh))

       {

          // WHEN NEITHER "-position/-p" NOR "-normal/-nr" ARE SPECIFIED, CREATE AND CONNECT A "pointOnMeshInfo" NODE AND RETURN ITS NODE NAME:

          if (!positionSpecified && !normalSpecified)

          {

             // CREATE THE NODE:

             nodeCreated = true;

             meshDagPath.extendToShape();

             MFnDependencyNode depNodeFn;

             if (pointOnMeshInfoName == "")

                depNodeFn.create("pointOnMeshInfo");

             else

                depNodeFn.create("pointOnMeshInfo", pointOnMeshInfoName);

             pointOnMeshInfoName = depNodeFn.name();

             // SET THE ".faceIndex" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (faceIndexSpecified)

             {

                MPlug faceIndexPlug = depNodeFn.findPlug("faceIndex");

                faceIndexPlug.setValue(faceIndex);

             }

             // SET THE ".relative" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (relativeSpecified)

             {

                MPlug relativePlug = depNodeFn.findPlug("relative");

                relativePlug.setValue(relative);

             }

             // SET THE ".parameterU" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (parameterUSpecified)

             {

                MPlug parameterUPlug = depNodeFn.findPlug("parameterU");

                parameterUPlug.setValue(parameterU);

             }

             // SET THE ".parameterV" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:

             if (parameterVSpecified)

             {

                MPlug parameterVPlug = depNodeFn.findPlug("parameterV");

                parameterVPlug.setValue(parameterV);

             }

             // CONNECT THE NODES:

             MPlug worldMeshPlug, inMeshPlug;

             inMeshPlug = depNodeFn.findPlug("inMesh");

             depNodeFn.setObject(meshDagPath.node());

             worldMeshPlug = depNodeFn.findPlug("worldMesh");

             worldMeshPlug = worldMeshPlug.elementByLogicalIndex(meshDagPath.instanceNumber());

             MDGModifier dgModifier;

             dgModifier.connect(worldMeshPlug, inMeshPlug);

             dgModifier.doIt();

             // SET COMMAND RESULT AND RETURN:

             setResult(pointOnMeshInfoName);

             return MStatus::kSuccess;

          }

          // OTHERWISE, COMPUTE THE POINT-POSITION AND NORMAL:

          else

             getPointAndNormal(meshDagPath, faceIndex, relative, parameterU, parameterV, point, normal);

       }

       // INVALID INPUT WHEN SPECIFIED/SELECTED NODE IS NOT A MESH NOR TRANSFORM:

       else

       {

          displayError("Invalid type!  Only a mesh or its transform can be specified!");

          return MStatus::kFailure;

       }

       // SET THE RETURN VALUES OF THE COMMAND'S RESULT TO BE AN ARRAY OF FLOATS OUTPUTTING THE POSITION AND/OR NORMAL:

       MDoubleArray result;

       if (positionSpecified)

       {

          result.append(point.x);

          result.append(point.y);

          result.append(point.z);

       }

       if (normalSpecified)

       {

          result.append(normal.x);

          result.append(normal.y);

          result.append(normal.z);

       }

       setResult(result);

       return MStatus::kSuccess;

    }

    // CALLED WHEN USER UNDOES THE COMMAND:

    MStatus pointOnMeshCommand::undoIt()

    {

       // MERELY DELETE THE "pointOnMeshInfo" NODE THAT WAS CREATED, IF ONE WAS CREATED:

       if (nodeCreated)

       {

          MString deleteCmd = "delete ";

          deleteCmd += pointOnMeshInfoName;

          MGlobal::executeCommand(deleteCmd);

       }

       return MStatus::kSuccess;

    }