// =========================================================================== // Copyright 2018 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. // =========================================================================== // // // Description: // Given a selected surface isoparm, move the seam to that position // if the surface is periodic in the given direction(s). If the user // selects an isoparm with a parameter value lying between two knot // values, the closer is chosen. // // Limitations: // Does not reorder weights on rational surfaces // Requires uniform knot sequences // The created surface has no history proc float[] getNurbsSurfaceKnots( string $srfName, int $dirUorV ) // // Description : // Get all the knots from the surface in the given direction { float $knots[] ; string $infoNode ; // create info Node. if( catch( $infoNode = `createNode surfaceInfo` ) ) { return $knots ; } // connect curve on to the info node. string $outAttr = $srfName + ".local" ; string $inAttr = $infoNode + ".is" ; connectAttr $outAttr $inAttr ; // read the knots. if(0 == $dirUorV) { $outAttr = $infoNode + ".knotsU" ; } else { $outAttr = $infoNode + ".knotsV" ; } $knots = `getAttr $outAttr` ; // delete curve info node. delete $infoNode ; // return the knots. return $knots; } proc doMoveNurbsSurfaceSeam(string $srf, int $nrowsU, int $nrowsV) // Do the move by transforming each CV in turn to its new location // { // get the surface size int $spansU = eval("getAttr " + $srf + ".spansU"); int $spansV = eval("getAttr " + $srf + ".spansV"); int $degreeU = eval("getAttr " + $srf + ".degreeU"); int $degreeV = eval("getAttr " + $srf + ".degreeV"); int $formU = eval("getAttr " + $srf + ".formU"); int $formV = eval("getAttr " + $srf + ".formV"); // check legal to move seam if($nrowsU != 0 && $formU != 2) { error (uiRes("m_moveNurbsSurfaceSeam.kSurfaceNotPeriodicU")); return; } if($nrowsV != 0 && $formV != 2) { error (uiRes("m_moveNurbsSurfaceSeam.kSurfaceNotPeriodicV")); return; } // get number of CVs int $cvsU = (2 == $formU) ? $spansU : $spansU + $degreeU; int $cvsV = (2 == $formV) ? $spansV : $spansV + $degreeV; // check valid move is requested if($nrowsU >= $cvsU || $nrowsV >= $cvsV) { error (uiRes("m_moveNurbsSurfaceSeam.kMoveTooLarge")); return; } // array to hold shifted CVs float $cvs[]; // array to hold a single CV float $cv[3]; // move CVs and store in array int $u = 0; int $v = 0; for($u = 0; $u<$cvsU; $u++) { for($v = 0; $v<$cvsV; $v++) { $cv = eval("xform -q -ws -t " + $srf + ".cv[" + $u + "][" + $v + "]"); int $newU = $u - $nrowsU; if($newU < 0) $newU = $newU + $cvsU; int $newV = $v - $nrowsV; if($newV < 0) $newV = $newV + $cvsV; for($dim=0; $dim<3; $dim++) { $cvs[3*($newU*$cvsV + $newV) + $dim] = $cv[$dim]; } } } // copy reordered CVs from array back to surface if(2 == $formV) { for($u = 0; $u<$cvsU; $u++) { for($v = 0; $v<$cvsV; $v++) { for($dim=0; $dim<3; $dim++) { $cv[$dim] = $cvs[3*($u*$cvsV + $v) + $dim]; } eval("xform -ws -t " + $cv[0] + " " + $cv[1] + " " + $cv[2] + " " + $srf + ".cv[" + $u + "][" + $v + "]"); } refresh; } } else { for($v = 0; $v<$cvsV; $v++) { for($u = 0; $u<$cvsU; $u++) { for($dim=0; $dim<3; $dim++) { $cv[$dim] = $cvs[3*($u*$cvsV + $v) + $dim]; } eval("xform -ws -t " + $cv[0] + " " + $cv[1] + " " + $cv[2] + " " + $srf + ".cv[" + $u + "][" + $v + "]"); } refresh; } } return; } global proc moveNurbsSurfaceSeam() { // get all selected items string $items[] = `ls -sl`; // Run filter to select only the NURBS surfaces global int $gSelectIsoparmsBit; string $srfList[] = `filterExpand -ex true -fullPath true -sm $gSelectIsoparmsBit`; int $len = size($srfList) ; if( $len != 1 ) { error (uiRes("m_moveNurbsSurfaceSeam.kMoveNurbsInvalSelection")); return; } // get surface from selection string $srf[] = `listRelatives -fullPath -parent $items[0]`; // get the knot value of the selected isoparm string $buffer[]; tokenize $srfList[0] "[|]" $buffer; float $selectedKnot = $buffer[size($buffer) - 1]; string $buffer2[]; tokenize $buffer[size($buffer) - 2] "." $buffer2; string $selectedDir = $buffer2[1]; int $dirUorV = -1; if(!strcmp($selectedDir, "u")) { $dirUorV = 0; } else if(!strcmp($selectedDir, "v")) { $dirUorV = 1; } else { error (uiRes("m_moveNurbsSurfaceSeam.kUnrecognizedSurfaceDir")); return; } // get degree (U or V) int $deg = 0; int $form = 0; if(0 == $dirUorV) { $deg = eval("getAttr " + $srf[0] + ".degreeU"); $form = eval("getAttr " + $srf[0] + ".formU"); } else { $deg = eval("getAttr " + $srf[0] + ".degreeV"); $form = eval("getAttr " + $srf[0] + ".formV"); } // check that the surface is really periodic in this direction!! if(2 != $form) { string $fmt = (uiRes("m_moveNurbsSurfaceSeam.kSurfaceNotPeriodic")); error `format -s $selectedDir $fmt`; return; } // get the knots on the surface in the selected direction float $knots[] = getNurbsSurfaceKnots($srf[0], $dirUorV); int $numKnots = size($knots); // check that the knots are indeed uniform int $i; float $interval = $knots[1] - $knots[0]; for($i=2; $i<$numKnots; $i++) { float $newInterval = $knots[$i] - $knots[$i-1]; if(abs($newInterval - $interval) > 0.01*$interval) { string $fmt = (uiRes("m_moveNurbsSurfaceSeam.kKnotsNotUniform")); error `format -s $selectedDir $fmt`; } } // find the closest surface knot to the selected isoparm int $closestKnot = $deg-1; float $closestDistance = abs($selectedKnot - $knots[$deg-1]); for($i=$deg; $i<=($numKnots-$deg); $i++) { float $distance = abs($knots[$i] - $selectedKnot); if($distance < $closestDistance) { $closestDistance = $distance; $closestKnot = $i; } } // check for zero move if(($deg-1) == $closestKnot || ($numKnots-$deg) == $closestKnot) { error (uiRes("m_moveNurbsSurfaceSeam.kSeamAlreadyExists")); return; } // do the move int $numSpansToMove = $closestKnot - ($deg-1); int $nrowsU = (0 == $dirUorV) ? $numSpansToMove : 0; int $nrowsV = (1 == $dirUorV) ? $numSpansToMove : 0; doMoveNurbsSurfaceSeam($srf[0], $nrowsU, $nrowsV); return; }