closestPointOnCurve/closestPointOnCurveCmd.cpp
 
 
 
closestPointOnCurve/closestPointOnCurveCmd.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: closestPointOnCurve v1.0

// FILE: closestPointOnCurveCmd.cpp

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

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

// AUTHOR: QT

// REFERENCES: -This plugin's concept is based off of the "closestPointOnSurface" node.

//             -The MEL script AEclosestPointOnSurfaceTemplate.mel was referred to for

//              the AE template MEL script that accompanies the closestPointOnCurve node.

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

// COMPILED AND TESTED ON: Maya 4.0 on Windows





// HEADER FILES:

#include "closestPointOnCurveCmd.h"

#include "closestTangentUAndDistance.h"

#include "closestPointOnCurveStrings.h"




// CONSTRUCTOR DEFINITION:

closestPointOnCurveCommand::closestPointOnCurveCommand()

{

}





// DESTRUCTOR DEFINITION:

closestPointOnCurveCommand::~closestPointOnCurveCommand()

{

}





// METHOD FOR CREATING AN INSTANCE OF THIS COMMAND:

void *closestPointOnCurveCommand::creator()

{

   return new closestPointOnCurveCommand;

}





// CREATES THE SYNTAX OBJECT FOR THE COMMAND:

MSyntax closestPointOnCurveCommand::newSyntax()

{

   MSyntax syntax;



   // INPUT FLAGS:

   syntax.addFlag("-na", "-name", MSyntax::kString);

   syntax.addFlag("-ip", "-inPosition", MSyntax::kDouble, MSyntax::kDouble, MSyntax::kDouble);



   // OUTPUT/QUERYABLE FLAGS:

   syntax.addFlag("-p", "-position");

   syntax.addFlag("-nr", "-normal");

   syntax.addFlag("-t", "-tangent");

   syntax.addFlag("-u", "-paramU");

   syntax.addFlag("-d", "-distance");



   // DEFINE BEHAVIOUR OF COMMAND ARGUMENT THAT SPECIFIES THE CURVE NODE:

   syntax.useSelectionAsDefault(true);

   syntax.setObjectType(MSyntax::kSelectionList, 1, 1);



   // MAKE COMMAND QUERYABLE AND NON-EDITABLE:

   syntax.enableQuery(true);

   syntax.enableEdit(false);



   return syntax;

}





// MAKE THIS COMMAND UNDOABLE:

bool closestPointOnCurveCommand::isUndoable() const

{

   return true;

}





// PARSE THE COMMAND'S FLAGS AND ARGUMENTS AND STORING THEM AS PRIVATE DATA, THEN DO THE WORK BY CALLING redoIt():

MStatus closestPointOnCurveCommand::doIt(const MArgList& args)

{

   // CREATE THE PARSER:

   MArgDatabase argData(syntax(), args);



   // STORE FLAG INDICATORS, STORING WHETHER EACH FLAG HAS BEEN SET OR NOT:

   queryFlagSet = argData.isQuery();

   inPositionFlagSet = argData.isFlagSet("inPosition");

   positionFlagSet = argData.isFlagSet("-position");

   normalFlagSet = argData.isFlagSet("-normal");

   tangentFlagSet = argData.isFlagSet("-tangent");

   paramUFlagSet = argData.isFlagSet("-paramU");

   distanceFlagSet = argData.isFlagSet("-distance");



   // STORE THE NAME OF THE "closestPointOnCurve" NODE IF SPECIFIED, OTHERWISE ASSIGN DEFAULT:

   if (argData.isFlagSet("-name"))

      argData.getFlagArgument("-name", 0, closestPointOnCurveNodeName);

   else

      closestPointOnCurveNodeName = "";



   // STORE THE "inPosition" IF SPECIFIED, OTHERWISE ASSIGN DEFAULT:

   if (inPositionFlagSet)

   {

      argData.getFlagArgument("-inPosition", 0, inPosition.x);

      argData.getFlagArgument("-inPosition", 1, inPosition.y);

      argData.getFlagArgument("-inPosition", 2, inPosition.z);

   }

   else

   {

      inPosition.x = 0.0;

      inPosition.y = 0.0;

      inPosition.z = 0.0;

   }



   // STORE THE SPECIFIED OBJECT, INPUTTED FROM EITHER THE COMMAND ARGUMENT OR CURRENT SELECTION:

   argData.getObjects(sList);



   return redoIt();

}





// COMPUTING THE OUTPUT VALUES FOR THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U AND DISTANCE, OR CREATING A "closestPointOnCurve" NODE:

MStatus closestPointOnCurveCommand::redoIt()

{

   // DOUBLE-CHECK TO MAKE SURE THERE'S A SPECIFIED OBJECT TO EVALUATE ON:

   if (sList.length() == 0)

   {
           MStatus stat;
           MString msg = MStringResource::getString(kNoValidObject, stat);
       displayError(msg);
       return MStatus::kFailure;
   }



   // RETRIEVE THE SPECIFIED OBJECT AS A DAGPATH:

   MDagPath curveDagPath;
   sList.getDagPath(0, curveDagPath);


   // CHECK FOR INVALID NODE-TYPE INPUT WHEN SPECIFIED/SELECTED NODE IS *NOT* A "CURVE" NOR "CURVE TRANSFORM":

   if (!curveDagPath.node().hasFn(MFn::kNurbsCurve) && !(curveDagPath.node().hasFn(MFn::kTransform) && curveDagPath.hasFn(MFn::kNurbsCurve)))

   {
           MStatus stat;
           MString msg; 
           // Use format to place variable string into message
           MString msgFmt = MStringResource::getString(kInvalidType, stat);
           MStringArray selectionStrings;
           sList.getSelectionStrings(0, selectionStrings);
           msg.format(msgFmt, selectionStrings[0]);
           displayError(msg);
       return MStatus::kFailure;
   }



   // WHEN COMMAND *NOT* IN "QUERY MODE" (I.E. "CREATION MODE"), CREATE AND CONNECT A "closestPointOnCurve" NODE AND RETURN ITS NODE NAME:

   if (!queryFlagSet)

   {

      // CREATE THE NODE:

      MFnDependencyNode depNodeFn;

      if (closestPointOnCurveNodeName == "")

         depNodeFn.create("closestPointOnCurve");

      else

         depNodeFn.create("closestPointOnCurve", closestPointOnCurveNodeName);

      closestPointOnCurveNodeName = depNodeFn.name();



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

      if (inPositionFlagSet)

      {

         MPlug inPositionXPlug = depNodeFn.findPlug("inPositionX");

         inPositionXPlug.setValue(inPosition.x);

         MPlug inPositionYPlug = depNodeFn.findPlug("inPositionY");

         inPositionYPlug.setValue(inPosition.y);

         MPlug inPositionZPlug = depNodeFn.findPlug("inPositionZ");

         inPositionZPlug.setValue(inPosition.z);

      }



      // MAKE SOME ADJUSTMENTS WHEN THE SPECIFIED NODE IS A "TRANSFORM" OF A CURVE SHAPE:

      unsigned instanceNumber=0;

      if (curveDagPath.node().hasFn(MFn::kTransform))

      {

         // EXTEND THE DAGPATH TO ITS CURVE "SHAPE" NODE:

         curveDagPath.extendToShape();



         // TRANSFORMS ARE *NOT* NECESSARILY THE "FIRST" INSTANCE TRANSFORM OF A CURVE SHAPE:

         instanceNumber = curveDagPath.instanceNumber();

      }



      // CONNECT THE NODES:

      MPlug worldCurvePlug, inCurvePlug;

      inCurvePlug = depNodeFn.findPlug("inCurve");

      depNodeFn.setObject(curveDagPath.node());

      worldCurvePlug = depNodeFn.findPlug("worldSpace");

      worldCurvePlug = worldCurvePlug.elementByLogicalIndex(instanceNumber);

      MDGModifier dgModifier;

      dgModifier.connect(worldCurvePlug, inCurvePlug);

      dgModifier.doIt();



      // SET COMMAND RESULT TO BE NEW NODE'S NAME, AND RETURN:

      setResult(closestPointOnCurveNodeName);

      return MStatus::kSuccess;

   }

   // OTHERWISE, WE'RE IN THE COMMAND'S "QUERY MODE":

   else

   {

      // COMPUTE THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U AND DISTANCE, USING THE *FIRST* INSTANCE TRANSFORM WHEN CURVE IS SPECIFIED AS A "SHAPE":

      MPoint position;

      MVector normal, tangent;

      double paramU, distance;

      closestTangentUAndDistance(curveDagPath, inPosition, position, normal, tangent, paramU, distance);



      // WHEN NO QUERYABLE FLAG IS SPECIFIED, INDICATE AN ERROR:

      if (!positionFlagSet && !normalFlagSet && !tangentFlagSet && !paramUFlagSet && !distanceFlagSet)

      {
                  MStatus stat;
                  MString msg = MStringResource::getString(kNoQueryFlag, stat);
                  displayError(msg);
          return MStatus::kFailure;
     }

      // WHEN JUST THE "DISTANCE" IS QUERIED, RETURN A SINGLE "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND:

      else if (distanceFlagSet && !(positionFlagSet || normalFlagSet || tangentFlagSet || paramUFlagSet))

         setResult(distance);

      // WHEN JUST THE "PARAMETER-U" IS QUERIED, RETURN A SINGLE "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND:

      else if (paramUFlagSet && !(positionFlagSet || normalFlagSet || tangentFlagSet || distanceFlagSet))

         setResult(paramU);

      // OTHERWISE, SET THE RETURN VALUE OF THE COMMAND'S RESULT TO A "COMPOSITE ARRAY OF FLOATS":

      else

      {

         // HOLDS FLOAT ARRAY RESULT:

         MDoubleArray floatArrayResult;



         // APPEND THE RESULTS OF THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U AND DISTANCE VALUES TO THE FLOAT ARRAY RESULT:

         if (positionFlagSet)

         {

            floatArrayResult.append(position.x);

            floatArrayResult.append(position.y);

            floatArrayResult.append(position.z);

         }

         if (normalFlagSet)

         {

            floatArrayResult.append(normal.x);

            floatArrayResult.append(normal.y);

            floatArrayResult.append(normal.z);

         }

         if (tangentFlagSet)

         {

            floatArrayResult.append(tangent.x);

            floatArrayResult.append(tangent.y);

            floatArrayResult.append(tangent.z);

         }

         if (paramUFlagSet)

            floatArrayResult.append(paramU);

         if (distanceFlagSet)

            floatArrayResult.append(distance);



         // FINALLY, SET THE COMMAND'S RESULT:

         setResult(floatArrayResult);

      }



      return MStatus::kSuccess;

   }

}





// CALLED WHEN USER UNDOES THE COMMAND:

MStatus closestPointOnCurveCommand::undoIt()

{

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

   if (!queryFlagSet)

   {

      MString deleteCmd = "delete ";

      deleteCmd += closestPointOnCurveNodeName;

      MGlobal::executeCommand(deleteCmd);

   }



   return MStatus::kSuccess;

}