//- // ========================================================================== // 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: closestPointOnMesh v1.0 // FILE: closestPointOnMeshCmd.cpp // DESCRIPTION: -Defines `closestPointOnMesh` 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 closestPointOnMesh node. // LAST UPDATED: Oct. 13th, 2001. // COMPILED AND TESTED ON: Maya 4.0 on Windows // HEADER FILES: #include "closestPointOnMeshCmd.h" #include "closestNormalUVAndFace.h" // CONSTRUCTOR DEFINITION: closestPointOnMeshCommand::closestPointOnMeshCommand() { } // DESTRUCTOR DEFINITION: closestPointOnMeshCommand::~closestPointOnMeshCommand() { } // METHOD FOR CREATING AN INSTANCE OF THIS COMMAND: void *closestPointOnMeshCommand::creator() { return new closestPointOnMeshCommand; } // CREATES THE SYNTAX OBJECT FOR THE COMMAND: MSyntax closestPointOnMeshCommand::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("-u", "-parameterU"); syntax.addFlag("-v", "-parameterV"); syntax.addFlag("-f", "-closestFaceIndex"); // DEFINE BEHAVIOUR OF COMMAND ARGUMENT THAT SPECIFIES THE MESH 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 closestPointOnMeshCommand::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 closestPointOnMeshCommand::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"); parameterUFlagSet = argData.isFlagSet("-parameterU"); parameterVFlagSet = argData.isFlagSet("-parameterV"); closestFaceIndexFlagSet = argData.isFlagSet("-closestFaceIndex"); // STORE THE NAME OF THE "closestPointOnMesh" NODE IF SPECIFIED, OTHERWISE ASSIGN DEFAULT: if (argData.isFlagSet("-name")) argData.getFlagArgument("-name", 0, closestPointOnMeshNodeName); else closestPointOnMeshNodeName = ""; // 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, UV AND FACE, OR CREATING A "closestPointOnMesh" NODE: MStatus closestPointOnMeshCommand::redoIt() { // DOUBLE-CHECK TO MAKE SURE THERE'S A SPECIFIED OBJECT TO EVALUATE ON: if (sList.length() == 0) { displayError("A mesh 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 meshDagPath; sList.getDagPath(0, meshDagPath); // CHECK FOR INVALID NODE-TYPE INPUT WHEN SPECIFIED/SELECTED NODE IS *NOT* A "MESH" NOR "MESH TRANSFORM": if (!meshDagPath.node().hasFn(MFn::kMesh) && !(meshDagPath.node().hasFn(MFn::kTransform) && meshDagPath.hasFn(MFn::kMesh))) { displayError("Invalid type! Only a mesh or its transform can be specified!"); return MStatus::kFailure; } // WHEN COMMAND *NOT* IN "QUERY MODE" (I.E. "CREATION MODE"), CREATE AND CONNECT A "closestPointOnMesh" NODE AND RETURN ITS NODE NAME: if (!queryFlagSet) { // CREATE THE NODE: MFnDependencyNode depNodeFn; if (closestPointOnMeshNodeName == "") depNodeFn.create("closestPointOnMesh"); else depNodeFn.create("closestPointOnMesh", closestPointOnMeshNodeName); closestPointOnMeshNodeName = 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 MESH SHAPE: unsigned instanceNumber=0; if (meshDagPath.node().hasFn(MFn::kTransform)) { // EXTEND THE DAGPATH TO ITS MESH "SHAPE" NODE: meshDagPath.extendToShape(); // TRANSFORMS ARE *NOT* NECESSARILY THE "FIRST" INSTANCE TRANSFORM OF A MESH SHAPE: instanceNumber = meshDagPath.instanceNumber(); } // CONNECT THE NODES: MPlug worldMeshPlug, inMeshPlug; inMeshPlug = depNodeFn.findPlug("inMesh"); depNodeFn.setObject(meshDagPath.node()); worldMeshPlug = depNodeFn.findPlug("worldMesh"); worldMeshPlug = worldMeshPlug.elementByLogicalIndex(instanceNumber); MDGModifier dgModifier; dgModifier.connect(worldMeshPlug, inMeshPlug); dgModifier.doIt(); // SET COMMAND RESULT TO BE NEW NODE'S NAME, AND RETURN: setResult(closestPointOnMeshNodeName); return MStatus::kSuccess; } // OTHERWISE, WE'RE IN THE COMMAND'S "QUERY MODE": else { // COMPUTE THE CLOSEST POSITION, NORMAL, U, V AND CLOSEST FACE INDEX, USING THE *FIRST* INSTANCE TRANSFORM WHEN MESH IS SPECIFIED AS A "SHAPE": MPoint position; MVector normal; double parameterU, parameterV; int closestFaceIndex; closestNormalUVAndFace(meshDagPath, inPosition, position, normal, parameterU, parameterV, closestFaceIndex); // WHEN NO QUERYABLE FLAG IS SPECIFIED, INDICATE AN ERROR: if (!positionFlagSet && !normalFlagSet && !parameterUFlagSet && !parameterVFlagSet && !closestFaceIndexFlagSet) { 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 "CLOSEST FACE INDEX" IS QUERIED, RETURN A SINGLE "INT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND: else if (closestFaceIndexFlagSet && !(positionFlagSet || normalFlagSet || parameterUFlagSet || parameterVFlagSet)) setResult(closestFaceIndex); // WHEN JUST THE "U PARAMETER" IS QUERIED, RETURN A SINGLE "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND: else if (parameterUFlagSet && !(positionFlagSet || normalFlagSet || parameterVFlagSet || closestFaceIndexFlagSet)) setResult(parameterU); // WHEN JUST THE "V PARAMETER" IS QUERIED, RETURN A SINGLE "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND: else if (parameterVFlagSet && !(positionFlagSet || normalFlagSet || parameterUFlagSet || closestFaceIndexFlagSet)) setResult(parameterV); // 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, U, V AND CLOSEST FACE INDEX 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 (parameterUFlagSet) floatArrayResult.append(parameterU); if (parameterVFlagSet) floatArrayResult.append(parameterV); if (closestFaceIndexFlagSet) floatArrayResult.append((double)closestFaceIndex); // FINALLY, SET THE COMMAND'S RESULT: setResult(floatArrayResult); } return MStatus::kSuccess; } } // CALLED WHEN USER UNDOES THE COMMAND: MStatus closestPointOnMeshCommand::undoIt() { // MERELY DELETE THE "closestPointOnMesh" NODE THAT WAS CREATED, IF ONE WAS CREATED: if (!queryFlagSet) { MString deleteCmd = "delete "; deleteCmd += closestPointOnMeshNodeName; MGlobal::executeCommand(deleteCmd); } return MStatus::kSuccess; }