//- // ========================================================================== // Copyright (C) 1995 - 2005 Alias Systems Corp. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files are provided by Alias // Systems Corp. ("Alias") and/or its licensors for the exclusive use of the // Customer (as defined in the Alias Software License Agreement that // accompanies this Alias software). Such Customer has the right to use, // modify, and incorporate the Data into other products and to distribute such // products for use by end-users. // // THE DATA IS PROVIDED "AS IS". ALIAS HEREBY DISCLAIMS ALL WARRANTIES // RELATING TO THE DATA, INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR // IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES // WHATSOEVER, WHETHER DIRECT, INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, OR IN EQUITY, // ARISING OUT OF ACCESS TO, USE OF, OR RELIANCE UPON THE DATA. // ========================================================================== //+ // DISCLAIMER: THIS PLUGIN IS PROVIDED AS IS. IT IS NOT SUPPORTED BY // ALIAS, 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" // 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) { displayError("A curve or its transform node must be specified as a command argument, or using your current selection."); 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))) { displayError("Invalid type! Only a curve or its transform can be specified!"); 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) { displayError("You must specify AT LEAST ONE queryable flag in query mode. Use the `help` command to list all available flags."); 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; }