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);
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
}
}
// 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;
}
}