//--------------------------------------------------------------------------------------------------
// The Gear Creator
// filename: gearCreator.mel
// Script written by: Colin Callahan
// email: colinmcallahan@gmail.com
// website: www.colinmcallahan.com
//
// ---The purpose of this script is to provide a quick and simple solution to creating chains(sets) of gears
// ---Gears are rigged on the fly to animate with their teeth accurately meshed together
// ---Controls provided for orienting the gears relative to the gear they are attached to
// ---There are various attributes that can be customized to create unique gear geometry within a set of gears
// ---2 creation methods: Gear by Gear and Random Gear
//
//--------------------------------------------------------------------------------------------------

// Procedure for handling node types
global proc string gearNodeType(string $strAction, string $strGearNode)
{
// variable for the resulting gear type name
string $strGearNodeType ;
switch ($strAction)
{
// Rename the node according to what it is
case "rename" :
if (`attributeExists "numTeeth" $strGearNode`)
{
$strGearNodeType = `rename $strGearNode ($strGearNode + "_gear")` ;
} else
{
$strGearNodeType = `rename $strGearNode ($strGearNode+ "_set")` ;
}
break ;

// Check for what type of node it is and return that
case "check" :
if (`endsWith $strGearNode "gear"`)
{
$strGearNodeType = "gear" ;
} else if (`endsWith $strGearNode "set"`)
{
$strGearNodeType = "set" ;
} else if (`endsWith $strGearNode "rotator"`)
{
$strGearNodeType = "rotator" ;
}
else if (`endsWith $strGearNode "axel"`)
{
$strGearNodeType = "axel" ;
}
break ;
}
// return either the renamed node or the type of the node
return $strGearNodeType ;
}

// Procedure for listing the children gears of a set
proc string[] listGears(string $strSetName)
{
// Variable for the gears collected
string $strGears[] ;
if ($strSetName == "scene")
{
// in the case that the user wants all the gears in the scene find them
// variable for the list of objects in the scene
string $strScene[] = `ls -tr`;
for ($node in $strScene)
{
if (`gearNodeType check $node` == "gear")
{
// in the case that the node is a gear, add it to the gears list
$strGears[`size($strGears)`] = $node ;
}
}
}
else
{
// in the case that the user wants the gears in a certain set find them
// variable for the children of the specified set
string $strSetChildren[] = `listRelatives -c -typ "transform" $strSetName` ;
for ($node in $strSetChildren)
{
if (`gearNodeType check $node` == "gear")
{
// in the case that the node is a gear add it to the gears list
$strGears[`size($strGears)`] = $node ;
}
else if (`gearNodeType check $node` == "rotator")
{
// in the case that the node is a rotator, add its child gear to the gears list
string $strRotatorChildren[] = `listRelatives -c -typ "transform" $node` ;
$strGears[`size($strGears)`] = $strRotatorChildren[1] ;
}
}
}
// return the gears list
return $strGears ;
}

// Procedure for handling gear materials
global proc gearMaterial(string $strGear,string $strMaterial)
{
// find the path to the texture images
string $strScriptPath = `internalVar -usd` ;
string $strImagePath = $strScriptPath + "/gearTextures" ;

// If necessary retrieve the desired material from the UI
if ($strMaterial == "UI")
{
// Query UI for the material
int $iRadioSelected = `radioButtonGrp -q -sl radioGearMaterial` ;
switch ($iRadioSelected)
{
case 1:
$strMaterial = "gearSteel" ;
break ;

case 2:
$strMaterial = "gearBronze" ;
break ;

case 3:
$strMaterial = "gearWood" ;
break ;
}
}
// Error check the incoming gear node to verify that it is in-fact a gear
else if (`gearNodeType check $strGear` != "gear" && `gearNodeType check $strGear` != "axel" && $strGear != "Gear_Temp")
{
error "Please select just one gear to assign a material to";
}

// Check to see if the material already exists
if (`objExists($strMaterial)`)
{
// in the case that the material already exists assign it to the gear
select $strGear ;
sets -e -forceElement ($strMaterial + "SG") ;
}
else
{
// In the case that the material does not exist create it
switch ($strMaterial)
{
case "gearSteel":
// create the necessary nodes and connect the necessary attributes
sets -n "gearSteelSG" -r 1 -nss 1 -em ;
shadingNode -n "gearSteel" -as blinn ;
connectAttr -f gearSteel.outColor gearSteelSG.surfaceShader ;
shadingNode -n "gearSteel_2dPlacement" -au place2dTexture ;
shadingNode -n "gearSteel_diffuse" -at file ;
defaultNavigation -connectToExisting -source gearSteel_2dPlacement -destination gearSteel_diffuse ;
connectAttr -f gearSteel_diffuse.outColor gearSteel.color ;

// Set the material attributes to provide the look of steel
setAttr -type "string" gearSteel_diffuse.fileTextureName ($strImagePath + "/steel.jpg") ;
setAttr "gearSteel.reflectivity" 0 ;
setAttr "gearSteel.specularColor" -type double3 8.0 8.0 8.0 ;
setAttr "gearSteel.specularRollOff" 0.5 ;
setAttr "gearSteel.eccentricity" 0.3 ;

// assign the material to the gear
select $strGear ;
sets -e -forceElement gearSteelSG ;
break ;

case "gearBronze":
// create the necessary nodes and connect the necessary attributes
sets -n "gearBronzeSG" -r 1 -nss 1 -em ;
shadingNode -n "gearBronze" -as anisotropic ;
connectAttr -f gearBronze.outColor gearBronzeSG.surfaceShader ;
shadingNode -n "gearBronze_2dPlacement" -au place2dTexture ;
shadingNode -n "gearBronze_diffuse" -at file ;
defaultNavigation -connectToExisting -source gearBronze_2dPlacement -destination gearBronze_diffuse ;
connectAttr -f gearBronze_diffuse.outColor gearBronze.color ;

// Set the material attributes to provide the look of bronze
setAttr -type "string" gearBronze_diffuse.fileTextureName ($strImagePath + "/bronze.jpg") ;
setAttr "gearBronze.specularColor" -type double3 1.0 0.85 0.40 ;
setAttr "gearBronze.angle" 180.00 ;
setAttr "gearBronze.anisotropicReflectivity" 0 ;
setAttr "gearBronze.reflectivity" 0.75;
setAttr "gearBronze.ambientColor" -type double3 0.1 0.1 0.1 ;

// assign the material to the gear
select $strGear ;
sets -e -forceElement gearBronzeSG ;
break ;

case "gearWood":
// create the necessary nodes and connect the necessary attributes
sets -n "gearWoodSG" -r 1 -nss 1 -em ;
shadingNode -n "gearWood" -as lambert ;
connectAttr -f gearWood.outColor gearWoodSG.surfaceShader ;
shadingNode -n "gearWood_2dPlacement" -au place2dTexture ;
shadingNode -n "gearWood_diffuse" -at file ;
defaultNavigation -connectToExisting -source gearWood_2dPlacement -destination gearWood_diffuse ;
connectAttr -f gearWood_diffuse.outColor gearWood.color ;

// Set the material attributes to provide the look of wood
setAttr -type "string" gearWood_diffuse.fileTextureName ($strImagePath + "/wood.jpg") ;
setAttr "gearWood_2dPlacement.repeatV" 5;
setAttr "gearWood_2dPlacement.repeatU" 5;

// assign the material to the gear
select $strGear ;
sets -e -forceElement gearWoodSG ;
break ;
}
}
// if the object is not an axel add a material attribute to it
if (`gearNodeType check $strGear` != "axel")
{
// if the material attribute does not exist add it
if (`attributeExists "gearMaterial" $strGear` == 0)
{
addAttr -ln "gearMaterial" -k 0 -dt "string" ;
}
// set the material attribute to the new material
setAttr -type "string" ($strGear + ".gearMaterial") $strMaterial ;
}
}

// Procedure for generating the detailed gear geometry from the temporary geometry and animating it
proc string createGear(string $strSetName, string $strGearType, string $strParentGear)
{
// Retrieve the necessary attributes from the temporary gear
float $fToothWidth = `getAttr ($strSetName + ".toothWidth")` ;
float $fToothLength = `getAttr ($strSetName + ".toothLength")` ;
float $fToothBevel = `getAttr ($strSetName + ".toothBevel")` ;
int $iNumTeeth = `getAttr "Gear_Temp.numTeeth"` ;
float $fRadius = `getAttr "Gear_Temp.radius"` ;
float $fHeight = `getAttr "Gear_Temp.height"` ;

// If there is a parent gear retrieve the necessary information from it
float $fParentHeight ;
string $strPastGearType = "";
float $fParentRadius = 0 ;
string $strParentRotator ;
if ($strParentGear != "none")
{
$fParentRadius = `getAttr ($strParentGear + ".radius")` ;
$strPastGearType = `getAttr ($strParentGear + ".gearType")`;
$fParentHeight = `getAttr ($strParentGear + ".height")`;
}

// If the parent gear also has a parent gear locate its rotator node
if (`attributeExists "gearParent" $strParentGear`)
{
$strParentRotator = ($strSetName + "|" + $strParentGear + "_rotator") ;
}

// find the next gear number available for naming to avoid conflicts
string $strGears[] = `listGears "scene"` ;
int $iGearNums[] ;
int $iGearNum ;
if (size($strGears) == 0)
{
$iGearNum = 0 ;
}
else
{
// gather the numbers from the gears
for ($gear in $strGears)
{
$iGearNums[`size($iGearNums)`] = `getAttr ($gear + ".gearNum")` ;
}
// Arrange the array in numerical order
int $iGearNumsSorted[] = `sort $iGearNums` ;
// Increment to the next highest gear number
$iGearNum = $iGearNumsSorted[`size($iGearNumsSorted)` - 1] + 1 ;
}

// Add the necessary attributes
select "Gear_Temp";
addAttr -ln "gearNum" -k 0 -hnv 0 -hxv 0 -at "short" -dv $iGearNum ;
addAttr -ln "gearType" -k 0 -dt "string" ;
setAttr -type "string" Gear_Temp.gearType $strGearType ;

// Create the detailed gear geometry
string $strChildGear ;
switch ($strGearType)
{
case "spur":
// Check if the parent gear is a face gear
if ($strParentGear != "none")
{
if (`getAttr ($strParentGear + ".gearType")` == "face")
{
// Place the gear to mesh its teeth to the parent
move -r ($fToothLength * -1) ($fParentHeight * 0.5) 0 Gear_Temp ;
}
else
{
// Place the gear to mesh its teeth to the parent
move -r ($fToothLength * -.1) 0 0 Gear_Temp ;
}
}

// Create the Teeth
for ($i = 0;$i < $iNumTeeth;$i++)
{
polyExtrudeFacet -kft 0 -d 1 -ltz $fToothLength -ls ($fToothBevel * .75) ($fToothBevel * .75) ($fToothBevel * .75) Gear_Temp.f[$i * 2] ;
}
for ($i = 0;$i < $iNumTeeth;$i++)
{
scaleComponents -ro 0 (($i + 1.25) * (360.00 / $iNumTeeth)) 0 -p `objectCenter -gl -x Gear_Temp` `objectCenter -gl -y Gear_Temp` `objectCenter -gl -z Gear_Temp` 1.0 1.0 $fToothBevel Gear_Temp.f[($i * 2) + 1] ;
}

// Create the Connector
polyExtrudeFacet -kft 0 -d 1 -ls .25 .25 1 Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ltz ($fHeight * 2) Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ls .75 .75 1 Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ltz ($fHeight * -3) Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ls .1875 .1875 1 Gear_Temp.f[$iNumTeeth * 2 + 1] ;
delete Gear_Temp.f[$iNumTeeth * 2] Gear_Temp.f[$iNumTeeth * 2 + 1] ;
select Gear_Temp ;
polyMergeVertex ;

// Automatically Soften the edges of the mesh
polySoftEdge -a 45 Gear_Temp ;

// Automatically UV map the gear
polyAutoProjection -l 2 -sc 1 -o 1 "Gear_Temp.f[*]" ;

// delete the construction history of the temp gear
delete -ch "Gear_Temp" ;

// Rename the gear
string $strCollapsedGear = `rename "Gear_Temp" ("Spur" + $iGearNum)` ;
$strChildGear = `gearNodeType "rename" $strCollapsedGear` ;

// Create an axel for the gear
string $strAxel[] = `polyCylinder -n ($strChildGear + "_axel") -r ($fRadius * .175) -h ($fHeight * 5)` ;
float $fAxelLoc[3] = `objectCenter ($strChildGear + "Shape")` ;

// Move the axel into place
move -a $fAxelLoc[0] $fAxelLoc[1] $fAxelLoc[2] $strAxel[0] ;

// Assign a material to the axel
gearMaterial $strAxel[0] "gearSteel" ;

// Animate the gear
if ($strParentGear != "none")
{
// Create the node for rotating children gears around their parents
string $strRotator[] = `circle -r ($fRadius + $fParentRadius - ($fToothLength * .25)) -nr 0 1 0 -n ($strChildGear + "_rotator")` ;

// collect position information in order to place the rotator
float $fParentLoc[3] = `objectCenter ($strParentGear + "Shape")` ;
float $fChildLocY = `objectCenter -y ($strChildGear + "Shape")` ;

// move the rotator into place
move -a $fParentLoc[0] ($fParentLoc[1] + $fParentHeight) $fParentLoc[2] $strRotator[0] ;
if ($strPastGearType == "face")
{
move -r 0 ($fToothLength * 2) 0 $strRotator[0] ;
}
// parent constrain rotator to parent gear to ignore rotation
parentConstraint -mo -sr "y" -n ($strRotator[0] + "_parentConstraint") $strParentGear $strRotator[0] ;

// parent the gear to its rotator
parent -a $strChildGear $strRotator[0] ;

// parent the rotator to the set
parent -a $strRotator[0] $strSetName ;


if (`attributeExists "gearParent" $strParentGear`)
{
// in the case that the parent gear has a parent gear also, base the child's rotation off of both of them
expression -n ("exprRotate_" + $strChildGear) -o $strChildGear -s ("rotateY = ((-" + $strParentGear + ".rotateY + " + $strRotator[0] + ".ry - " + $strParentRotator + ".ry) * (" + $strParentGear + ".numTeeth / " + $strChildGear + ".numTeeth)) + (360 / " + $strChildGear + ".numTeeth)") ;
} else
{
// in the case that there is a parent gear, base the child's rotation off of it
expression -n ("exprRotate_" + $strChildGear) -o $strChildGear -s ("rotateY = ((-" + $strParentGear + ".rotateY + " + $strRotator[0] + ".ry) * (" + $strParentGear + ".numTeeth / " + $strChildGear + ".numTeeth)) + (360 / " + $strChildGear + ".numTeeth)") ;
}
} else
{
// In the case this is the first gear in the set, add a rotation with speed multiplier attribute from gear set
expression -n ("exprRotateMaster_" + $strChildGear) -s ($strChildGear + ".rotateY = time * " + $strSetName + ".rotationSpeed ;") ;

// parent the gear to the set
parent -a $strChildGear $strSetName ;
}
// parent constrain axel to gear
parentConstraint -mo -n ($strAxel[0] + "_parentConstraint") $strChildGear $strAxel[0] ;
break ;

case "face":
// Add to the radius to provide accurately sized teeth
float $fNewRadius = $fRadius + $fToothLength ;
setAttr Gear_Temp_Geo.radius $fNewRadius ;

// Place the gear to mesh its teeth to the parent
if ($strParentGear != "none")
{
move -r ($fToothLength * -.25) (($fHeight * -.5) + ($fToothLength * -.5)) 0 Gear_Temp ;
}

// Inset the Top Face to provide faces to create teeth from
polyExtrudeFacet -kft 0 -d 1 -ls ($fRadius / $fNewRadius) ($fRadius / $fNewRadius) 1 Gear_Temp.f[$iNumTeeth * 2 + 1] ;

// extrude the teeth on every other face
for ($i = 0;$i < $iNumTeeth;$i++)
{
polyExtrudeFacet -kft 0 -d 1 -ltz $fToothLength -ls ($fToothBevel * .75) ($fToothBevel * .75) ($fToothBevel * .75) Gear_Temp.f[($iNumTeeth * 2 + 2) + ($i * 2)] ;
}

// scale down the faces in between the teeth to provide the necessary bevel
for ($i = 0;$i < $iNumTeeth;$i++)
{
scaleComponents -ro 0 (($i + 1.25) * (360.00 / $iNumTeeth)) 0 -p `objectCenter -gl -x Gear_Temp` `objectCenter -gl -y Gear_Temp` `objectCenter -gl -z Gear_Temp` 1.0 1.0 $fToothBevel Gear_Temp.f[($iNumTeeth * 2 + 2) + ($i * 2 + 1)] Gear_Temp.f[$i * 2 + 1] ;
//scaleComponents -ro 0 (($i + 1) * (360.00 / $iNumTeeth)) 0 -p `objectCenter -gl -x Gear_Temp` `objectCenter -gl -y Gear_Temp` `objectCenter -gl -z Gear_Temp` ($fNewRadius * 1.125) 1.0 1.0 Gear_Temp.f[($iNumTeeth * 2 + 2) + ($i * 2)];
}

// Create the Connector
polyExtrudeFacet -kft 0 -d 1 -ls (($fRadius / $fNewRadius) * .25) (($fRadius / $fNewRadius) * .25) 1 Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ltz ($fHeight * 2) Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ls .75 .75 1 Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ltz ($fHeight * -3) Gear_Temp.f[$iNumTeeth * 2] ;
polyExtrudeFacet -kft 0 -d 1 -ls 0.1875 0.1875 1 Gear_Temp.f[$iNumTeeth * 2 + 1] ;
delete Gear_Temp.f[$iNumTeeth * 2] Gear_Temp.f[$iNumTeeth * 2 + 1] ;
select Gear_Temp ;
polyMergeVertex ;

// Automatically Soften the edges of the mesh
polySoftEdge -a 45 Gear_Temp ;

// Automatically UV map the gear
polyAutoProjection -l 2 -sc 1 -o 1 "Gear_Temp.f[*]" ;

// delete the construction history of the temp gear
delete -ch "Gear_Temp" ;

// Rename the gear
string $strCollapsedGear = `rename "Gear_Temp" ("Face" + $iGearNum)` ;
$strChildGear = `gearNodeType rename $strCollapsedGear` ;

// Create an axel for the gear
string $strAxel[] = `polyCylinder -n ($strChildGear + "_axel") -r ($fRadius * .175) -h ($fHeight * 5)` ;
float $fAxelLoc[3] = `objectCenter ($strChildGear + "Shape")` ;

// move the axel into place
move -a $fAxelLoc[0] $fAxelLoc[1] $fAxelLoc[2] $strAxel[0] ;

// Assign a material to the axel
gearMaterial $strAxel[0] "gearSteel" ;

// Animate the gear
if ($strParentGear != "none")
{
// Create the node for rotating children gears around their parents
string $strRotator[] = `circle -r ($fNewRadius + $fParentRadius + ($fToothLength * .25)) -nr 0 1 0 -n ($strChildGear + "_rotator")` ;

// move the rotator node into place above the parent gear
float $fParentLoc[3] = `objectCenter ($strParentGear + "Shape")` ;
float $fChildLocY = `objectCenter -y ($strChildGear + "Shape")` ;
move -a $fParentLoc[0] ($fParentLoc[1] + $fParentHeight) $fParentLoc[2] $strRotator[0] ;

// parent constrain rotator to parent gear to ignore rotation
parentConstraint -mo -sr "y" -n ($strRotator[0] + "_parentConstraint") $strParentGear $strRotator[0] ;

// parent the gear to its rotator
parent -a $strChildGear $strRotator[0] ;

// parent the rotator to the set
parent -a $strRotator[0] $strSetName ;

if (`attributeExists "gearParent" $strParentGear`)
{
// in the case that the parent gear has a parent, base the current gear's rotation off both of them
expression -n ("exprRotate_" + $strChildGear) -o $strChildGear -s ("rotateY = ((-" + $strParentGear + ".rotateY + " + $strRotator[0] + ".ry - " + $strParentRotator + ".ry) * (" + $strParentGear + ".numTeeth / " + $strChildGear + ".numTeeth)) + (360 / " + $strChildGear + ".numTeeth)") ;
} else
{
// in the case that there is a parent gear, base the child gear's rotation off of it
expression -n ("exprRotate_" + $strChildGear) -o $strChildGear -s ("rotateY = ((-" + $strParentGear + ".rotateY + " + $strRotator[0] + ".ry) * (" + $strParentGear + ".numTeeth / " + $strChildGear + ".numTeeth)) + (360 / " + $strChildGear + ".numTeeth)") ;
}
} else
{
// In the case this is the first gear in the set, add a rotation with speed multiplier attribute from gear set
expression -n ("exprRotateMaster_" + $strChildGear) -s ($strChildGear + ".rotateY = time * " + $strSetName + ".rotationSpeed ;") ;
parent -a $strChildGear $strSetName ;
}

// parent constrain axel to gear
parentConstraint -mo -n ($strAxel[0] + "_parentConstraint") $strChildGear $strAxel[0] ;

// Update the radius attribute
setAttr ($strChildGear + ".radius") $fNewRadius ;
break ;
}
return $strChildGear;
}

// Procedure for recreating a single gear
proc string reCreateGear(string $strGear, string $strParentGear)
{
// retrieve the set that the gear is under
string $strGearSet = `getAttr ($strGear + ".gearSet")` ;

// Calculate the new radius with the new tooth width
// --
// retrieve the old radius
float $fRadius = `getAttr ($strGear + ".radius")` ;

// Recalculate the number of teeth based on the new tooth width
int $iSubD = $fRadius / `getAttr ($strGearSet + ".toothWidth")` ;
if ($iSubD % 2 != 0)
{
$iSubD++ ;
if (($iSubD / 2) % 2 != 0)
{
$iSubD += 2;
}
}
else if (($iSubD / 2) % 2 != 0)
{
$iSubD += 2;
}
else if ($iSubD < 12)
{
$iSubD = 12;
}
// Recalculate the radius based on the new number of teeth
int $iNumTeeth = $iSubD / 2;
$fRadius = `getAttr ($strGearSet + ".toothWidth")` * $iSubD ;

// Collect the remaining information from the old gear
float $fHeight = `getAttr ($strGear+ ".height")` ;
float $fToothLength = `getAttr ($strGearSet + ".toothLength")` ;
string $strGearType = `getAttr ($strGear + ".gearType")` ;
string $strRotator[] ;
float $fRotatorRotY ;
float $fParentHeight ;
string $strMaterial = `getAttr ($strGear + ".gearMaterial")` ;

// If there is a parent retrieve the necessary information from it
string $strParentGearType ;
float $fParentPosition[3] ;
if ($strParentGear != "none")
{
$strParentGearType = `getAttr ($strParentGear + ".gearType")` ;
$strRotator = `listRelatives -p -typ "transform" $strGear`;
$fRotatorRotY = `getAttr ($strRotator[0] + ".ry")` ;
$fParentPosition = `objectCenter $strParentGear` ;
$fParentHeight = `getAttr ($strParentGear + ".height")` ;
}

// recreate the old gear
// --
// temp gear to send to createGear
polyCylinder -r $fRadius -h $fHeight -sx $iSubD -n "Gear_Temp" ;

// Locate and rename the geometry node in the construction history of the temp gear
string $strGeoNode[] = `listHistory -af -pdo 1 "Gear_Temp"` ;
rename $strGeoNode[0] "Gear_Temp_Geo" ;

// move the temp gear into place
if ($strParentGear != "none")
{
move -a ($fParentPosition[0] + $fRadius + `getAttr ($strParentGear + ".radius")` + $fToothLength) ($fParentPosition[1] + $fParentHeight) $fParentPosition[2] "Gear_Temp" ;
} else
{
move -a `getAttr ($strGearSet + ".tx")` `getAttr ($strGearSet + ".ty")` `getAttr ($strGearSet + ".tz")` "Gear_Temp" ;
}

// add vital attributes to the temporary geometry node
select "Gear_Temp" ;
addAttr -ln "numTeeth" -k 0 -hnv 0 -hxv 0 -at "short" -dv $iNumTeeth ;
addAttr -ln "radius" -k 0 -hnv 0 -hxv 0 -at "float" -dv $fRadius ;
addAttr -ln "height" -k 0 -hnv 0 -hxv 0 -at "float" -dv $fHeight ;
addAttr -ln "gearSet" -k 0 -dt "string" ;
setAttr -type "string" Gear_Temp.gearSet $strGearSet ;
gearMaterial Gear_Temp $strMaterial ;
if ($strParentGear != "none")
{
addAttr -ln "gearParent" -k 0 -dt "string" ;
setAttr -type "string" Gear_Temp.gearParent $strParentGear ;
}
// un-parent the old gear
parent -w $strGear ;
// delete the old gear, its axel, and rotator if necessary
delete $strGear ;
delete ($strGear + "_axel") ;
if ($strParentGear != "none")
{
delete $strRotator[0] ;
}
// Create the new gear geometry
$strNewGear = `createGear $strGearSet $strGearType $strParentGear`;
// rotate the gear to match origional orientation
if ($strParentGear != "none")
{
rotate -r 0 $fRotatorRotY 0 ($strNewGear + "_rotator") ;
}
return $strNewGear ;
}

// Procedure for randomly generating gears
proc string createRandomGear(string $strParentGear)
{
// Parent variables
float $fParentLoc[3] ;
float $fParentHeight ;
float $fParentRadius ;
string $strParentType ;

// Find the name of the working set
string $strSetName ;
if ($strParentGear == "none")
{
string $strSelected[] = `ls -sl -tr` ;
$strSetName = $strSelected[0] ;
}
else
{
$strSetName = `getAttr ($strParentGear + ".gearSet")` ;
$fParentLoc = `objectCenter $strParentGear` ;
$fParentHeight = `getAttr ($strParentGear + ".height")` ;
$fParentRadius = `getAttr ($strParentGear + ".radius")` ;
$strParentType = `getAttr ($strParentGear + ".gearType")` ;
}

// Set location
float $fSetLoc[3] ;
$fSetLoc[0] = `getAttr ($strSetName + ".tx")` ;
$fSetLoc[1] = `getAttr ($strSetName + ".ty")` ;
$fSetLoc[2] = `getAttr ($strSetName + ".tz")` ;

// Gather the necessary information from the gear set
float $fToothWidth = `getAttr ($strSetName + ".toothWidth")` ;
float $fToothLength = `getAttr ($strSetName + ".toothLength")` ;
float $fToothBevel = `getAttr ($strSetName + ".toothBevel")` ;

// Query the UI for gear type probabilities
float $fSpurChance = `floatSliderGrp -q -v floatSldrSpurChance` ;
float $fFaceChance = `floatSliderGrp -q -v floatSldrFaceChance` ;

// Query the UI for material probabilities
float $fSteelChance = `floatSliderGrp -q -v floatSldrSteelChance` ;
float $fBronzeChance = `floatSliderGrp -q -v floatSldrBronzeChance` ;
float $fWoodChance = `floatSliderGrp -q -v floatSldrWoodChance` ;

// Query the UI for min and max values of radius, height, and orientation angle
float $fRadiusMin = `floatField -q -v floatFldRadiusMin` ;
float $fRadiusMax = `floatField -q -v floatFldRadiusMax` ;
float $fHeightMin = `floatField -q -v floatFldHeightMin` ;
float $fHeightMax = `floatField -q -v floatFldHeightMax` ;
int $iAngleMin = `intField -q -v intFldAngleMin` ;
int $iAngleMax = `intField -q -v intFldAngleMax` ;

// Determine the type of gear to create based on the chance values
string $strGearType ;
float $fPercentage = rand(0,($fSpurChance + $fFaceChance)) ;
if ($fPercentage >= 0 && $fPercentage <= $fSpurChance)
{
$strGearType = "spur" ;
} else if ($fPercentage > $fSpurChance && $fPercentage <= ($fSpurChance + $fFaceChance))
{
$strGearType = "face" ;
}
// check for conflicting gear types between parent and child
if ($strGearType == "face" && $strParentType == "face")
{
$strGearType = "spur" ;
}

// Determine the material to apply based on the chance values
string $strMaterial ;
$fPercentage = rand(0,($fSteelChance + $fBronzeChance + $fWoodChance)) ;
if ($fPercentage > 0 && $fPercentage <= $fSteelChance)
{
$strMaterial = "gearSteel" ;
}
else if ($fPercentage > $fSteelChance && $fPercentage <= ($fSteelChance + $fBronzeChance))
{
$strMaterial = "gearBronze" ;
}
else if ($fPercentage > ($fSteelChance + $fBronzeChance) && $fPercentage <= ($fSteelChance + $fBronzeChance + $fWoodChance))
{
$strMaterial = "gearWood" ;
}

// Calculate the random gear characteristics
float $fHeight = rand($fHeightMin,$fHeightMax) ;
int $fAngle = rand($iAngleMin,$iAngleMax) ;
float $fRandRadius = rand($fRadiusMin,$fRadiusMax) ;

// Recalculate the number of teeth based on the new tooth width
int $iSubD = $fRandRadius / $fToothWidth ;
if ($iSubD % 2 != 0)
{
$iSubD++ ;
if (($iSubD / 2) % 2 != 0)
{
$iSubD += 2;
}
}
else if (($iSubD / 2) % 2 != 0)
{
$iSubD += 2;
}
else if ($iSubD < 12)
{
$iSubD = 12;
}
// Recalculate the radius based on the new number of teeth
int $iNumTeeth = $iSubD / 2;
float $fRadius = $fToothWidth * $iSubD ;

// temp gear to send to createGear
polyCylinder -r $fRadius -h $fHeight -sx $iSubD -n "Gear_Temp" ;

// Locate and rename the geometry node in the construction history of the temp gear
string $strGeoNode[] = `listHistory -af -pdo 1 "Gear_Temp"` ;
rename $strGeoNode[0] "Gear_Temp_Geo" ;

// move the temp gear into place
if ($strParentGear != "none")
{
move -a ($fParentLoc[0] + $fRadius + $fParentRadius + $fToothLength) ($fParentLoc[1] + $fParentHeight) $fParentLoc[2] "Gear_Temp" ;
} else
{
move -a $fSetLoc[0] $fSetLoc[1] $fSetLoc[2] "Gear_Temp" ;
}

// add vital attributes to the temporary geometry node
select "Gear_Temp" ;
addAttr -ln "numTeeth" -k 0 -hnv 0 -hxv 0 -at "short" -dv $iNumTeeth ;
addAttr -ln "radius" -k 0 -hnv 0 -hxv 0 -at "float" -dv $fRadius ;
addAttr -ln "height" -k 0 -hnv 0 -hxv 0 -at "float" -dv $fHeight ;
addAttr -ln "gearSet" -k 0 -dt "string" ;
setAttr -type "string" Gear_Temp.gearSet $strSetName ;
// Apply the material to the gear
gearMaterial Gear_Temp $strMaterial ;
if ($strParentGear != "none")
{
addAttr -ln "gearParent" -k 0 -dt "string" ;
setAttr -type "string" Gear_Temp.gearParent $strParentGear ;
}
// Create the new gear geometry
string $strGear = `createGear $strSetName $strGearType $strParentGear`;
// rotate the gear to the random angle
if ($strParentGear != "none")
{
rotate -r 0 $fAngle 0 ($strGear + "_rotator") ;
}
return $strGear ;
}

// Procedure for creating and deleting a temporary builder gear
global proc tempGear(string $strAction, string $strGearSet, string $strParentGear, string $strGearType)
{
switch ($strAction)
{
case "create" :
// Temporary piece of gear geometry
float $fToothWidth = `getAttr ($strGearSet + ".toothWidth")` ;
float $fToothLength = `getAttr ($strGearSet + ".toothLength")` ;
string $strTempGear[] = `polyCylinder -r ($fToothWidth * 10) -h ($fToothWidth * 4) -sx 10 -n "Gear_Temp"` ;

// Locator nodes for real-time sizing
// ----------------------------------------
// --- Top Node
circle -r ($fToothWidth * 10) -nr 0 1 0 -n "Top" ;
move -a 0 ($fToothWidth * 4) 0 ;
// Locate and rename the geometry node in the construction history of the node
string $strGeoNode[] = `listHistory -af -pdo 1 "Top"` ;
rename $strGeoNode[0] "Top_Geo" ;

// --- Edge Node
circle -r $fToothWidth -nr 1 0 0 -n "Edge" ;
move -a ($fToothWidth * 10) ($fToothWidth * 4) 0 ;
// Locate and rename the geometry node in the construction history of the node
$strGeoNode = `listHistory -af -pdo 1 "Edge"` ;
rename $strGeoNode[0] "Edge_Geo" ;

// Parent the real time sizing nodes correctly
parent -a "Edge" "Top" ;
parent -r "Top" $strTempGear[0] ;

// in the case that the gear is the first in the set, position it at the set node
if ($strParentGear == "none")
{
move -a `getAttr ($strGearSet + ".tx")` `getAttr ($strGearSet + ".ty")` `getAttr ($strGearSet + ".tz")` $strTempGear[0] ;
}
// Locate and rename the geometry node in the construction history of the node
$strGeoNode = `listHistory -af -pdo 1 "Gear_Temp"` ;
rename $strGeoNode[0] "Gear_Temp_Geo" ;

// Expressions for real-time sizing
expression -n "exprTempGearRadius" -s ("Gear_Temp_Geo.radius = Gear_Temp_Geo.sa * " + $strGearSet + ".toothWidth ; Top_Geo.radius = Gear_Temp_Geo.radius") ;
expression -n "exprTempGearHeight" -s ("Gear_Temp_Geo.height = (Top.translateY * 2) - " + ($fToothWidth * 2) + " ; Edge_Geo.radius = Top.translateY") ;
expression -n "exprTempGearSubD" -s ("int $iSubD = (abs(Edge.translateX - Top.translateX) / " + $strGearSet + ".toothWidth) ; if ($iSubD % 2 != 0) {$iSubD ++; if (($iSubD / 2) % 2 != 0){$iSubD += 2;};}else if (($iSubD / 2) % 2 != 0){$iSubD += 2;};Gear_Temp_Geo.sa = $iSubD ;") ;
if ($strParentGear != "none")
{
float $fParentLoc[3] = `objectCenter $strParentGear` ;
float $fParentHeight = `getAttr ($strParentGear + ".height")` ;
move -a $fParentLoc[0] ($fParentLoc[1] + $fParentHeight) $fParentLoc[2] $strTempGear[0] ;
expression -n "exprTempGearPlacement" -s ($strTempGear[0] + ".tx = (" + $fParentLoc[0] + " + " + $strParentGear + ".radius + Gear_Temp_Geo.radius) + " + $fToothLength) ;
}
break;

case "cleanup" :
// Carry over vital attributes from the temporary geometry node
select "Gear_Temp" ;
addAttr -ln "numTeeth" -k 0 -hnv 0 -hxv 0 -at "short" -dv (`getAttr "Gear_Temp_Geo.sa"` / 2) ;
addAttr -ln "radius" -k 0 -hnv 0 -hxv 0 -at "float" -dv (`getAttr "Gear_Temp_Geo.radius"`) ;
addAttr -ln "height" -k 0 -hnv 0 -hxv 0 -at "float" -dv (`getAttr "Gear_Temp_Geo.height"`) ;
addAttr -ln "gearSet" -k 0 -dt "string" ;
setAttr -type "string" Gear_Temp.gearSet $strGearSet ;
if ($strParentGear != "none")
{
addAttr -ln "gearParent" -k 0 -dt "string" ;
setAttr -type "string" Gear_Temp.gearParent $strParentGear ;
delete "exprTempGearPlacement" ;
}
// Delete expressions and nodes used in real-time sizing
delete "Top" "Edge" "exprTempGearRadius" "exprTempGearHeight" "exprTempGearSubD" ;

// assign the material from the UI
gearMaterial "Gear_Temp" "UI" ;

// create the detailed gear geometry
createGear $strGearSet $strGearType $strParentGear ;

// close the finishing window
deleteUI gearCreatorTempWindow ;
break ;
}
}

// Procedure for creating and deleting gear sets
global proc gearSet(string $strAction)
{
// Variables to hold the list of sets in the scene
string $strScene[] = `ls -tr` ;
string $strSets[] ;
for ($node in $strScene)
{
if (`gearNodeType check $node` == "set")
{
$strSets[`size($strSets)`] = $node ;
}
}

// Variable for the selected objects
string $strSelection[] = `ls -sl -tr` ;

switch ($strAction)
{
case "create" :
// Query the UI for the new set name
string $strNewSetName = `textFieldGrp -q -text txtFieldNewSet` ;

// Error check for an existing name
for ($existingSetName in $strSets)
{
if ($strNewSetName + "_set" == $existingSetName)
{
error "There is already a Gear Set with this name, use a different name" ;
}
}
// Query the UI for the new set's information
float $fToothWidth = `floatSliderGrp -q -v floatSldrToothWidth` ;
float $fToothLength = `floatSliderGrp -q -v floatSldrToothLength` ;
float $fToothBevel = `floatSliderGrp -q -v floatSldrToothBevel` ;

// The locator node and its vital attributes
spaceLocator -n $strNewSetName -p 0 10 0 ;
addAttr -at "float" -ln "toothWidth" -h 0 -k 0 -min .01 -hxv 0 -dv $fToothWidth ;
addAttr -at "float" -ln "toothLength" -h 0 -k 0 -min .01 -hxv 0 -dv $fToothLength ;
addAttr -at "float" -ln "toothBevel" -h 0 -k 0 -min .01 -hxv 0 -dv $fToothBevel ;
addAttr -at "float" -ln "rotationSpeed" -h 0 -k 1 -hnv 0 -hxv 0 -dv 50.0 ;
gearNodeType "rename" $strNewSetName ;
break ;

case "delete" :
if (`size($strSelection)` > 1 || `gearNodeType check $strSelection[0]` != "set")
{
error "you must select only 1 gear set node for deletion. NOTE: This will delete all gears contained within the selected set node" ;
} else
{
string $strSetName = $strSelection[0] ;
// Delete the set node and all of its children
string $strSetMembers[] = `listGears $strSetName` ;
string $strAxels[] ;
for ($gear in $strSetMembers)
{
$strAxels[`size($strAxels)`] = $gear + "_axel" ;
}
delete $strSetMembers $strSetName $strAxels ;
}
break ;

case "rebuild" :
// Error check the selection
if (`size($strSelection)` > 1 || `gearNodeType check $strSelection[0]` != "set" || `size($strSelection)` <= 0)
{
error "Please select only one Gear Set to rebuild" ;
}
// Set the Gear Set's tooth width to match the value in the UI
setAttr ($strSelection[0] + ".toothWidth") `floatSliderGrp -q -v floatSldrToothWidth` ;
setAttr ($strSelection[0] + ".toothLength") `floatSliderGrp -q -v floatSldrToothLength` ;
setAttr ($strSelection[0] + ".toothBevel") `floatSliderGrp -q -v floatSldrToothBevel` ;

// Variables needed for reconstruction loop
string $strGears[] = `listGears $strSelection[0]` ;
string $strPastGear = "none" ;
// Rebuild the gears
for ($gear in $strGears)
{
string $strNewGear = `reCreateGear $gear $strPastGear` ;
$strPastGear = $strNewGear ;
}
select $strSelection[0] ;
break ;

case "setRotationSpeed" :
// Error check the selection
if (`size($strSelection)` > 1 || `gearNodeType check $strSelection[0]` != "set" || `size($strSelection)` <= 0)
{
error "Please select only one Gear Set to change the rotation speed" ;
}
// Set the Gear Set's rotation speed to match the value in the UI
setAttr ($strSelection[0] + ".rotationSpeed") `floatFieldGrp -q -v1 floatFieldRotationSpeed` ;
break;

case "createRandomGears":
// Error Check the selection
if (`gearNodeType check $strSelection[0]` != "gear" && `gearNodeType check $strSelection[0]` != "set" || `size($strSelection)` > 1)
{
error "Please select one gear or one gear set to build random gears" ;
}
string $strPastGear = "none" ;

if (`gearNodeType check $strSelection[0]` == "gear")
{
$strPastGear = $strSelection[0] ;
}

// Query the UI for how many gears to randomly create
int $iNumGears = `intFieldGrp -q -v1 intFldNumGears` ;

// Rebuild the gears
for ($i = 0;$i < $iNumGears;$i++)
{
string $strNewGear = `createRandomGear $strPastGear` ;
$strPastGear = $strNewGear ;
}
break ;

case "selectFromGear":
// Error Check the selection
if (`gearNodeType check $strSelection[0]` != "gear")
{
error "Please select one gear in order to select the set it is a part of" ;
}

// find the name of the set the gear belongs to and select it
select `getAttr ($strSelection[0] + ".gearSet")` ;
break ;
}
}

// Procedure for the FINISHED window of gear by gear creation
global proc gearCreateWindow()
{
// variable for parent gear
string $strParentGear ;

// variable for the set name
string $strSetName ;

// Variable for the type of gear to create
string $strGearType ;
string $strParentGearType ;

// Query UI for the type of gear to create
int $iRadioSelected = `radioButtonGrp -q -sl radioGearType` ;
switch ($iRadioSelected)
{
case 1:
$strGearType = "spur" ;
break ;

case 2:
$strGearType = "face" ;
break ;
}
// error check the selected object
string $strSelection[] = `ls -sl -tr` ;
if (`size($strSelection)` > 1 || (`gearNodeType check $strSelection[0]` != "gear" && `gearNodeType check $strSelection[0]` != "set"))
{
error "Select only one Gear Set or only one Gear before building a new gear" ;
}
// Provide the temporary builder gear based on what is selected
if (`gearNodeType check $strSelection[0]` == "gear")
{
$strParentGear = $strSelection[0] ;
$strSetName = `getAttr ($strSelection[0] + ".gearSet")` ;
$strParentGearType = `getAttr ($strParentGear + ".gearType")` ;

// Error check for conflicting gear types
if ($strGearType == "face" && $strParentGearType == "face")
{
error "Please choose a different type of gear to create. A face gear cannot be attached to another face gear";
deleteUI gearCreatorTempWindow ;
}
tempGear create $strSetName $strParentGear " " ;
} else if (`gearNodeType check $strSelection[0]` == "set")
{
$strParentGear = "none" ;
$strSetName = $strSelection[0] ;
tempGear create $strSetName $strParentGear " " ;
}

// Check for the window existing and erase if necessary
if (`window -exists gearCreatorTempWindow`)
{
deleteUI gearCreatorTempWindow ;
}
window -t "Gear Creator" -rtf 1 gearCreatorTempWindow ;
columnLayout -rs 5 ;
//Introduction Info
text -l "Size the gear, then click the FINISHED button" ;
button -l "FINISHED" -c ("tempGear cleanup " + $strSetName + " " + $strParentGear + " " + $strGearType) ;
showWindow gearCreatorTempWindow ;
}

// Procedure for the main UI window
global proc gearCreator()
{
// Check for the window existing and erase if necessary
if (`window -exists gearCreatorMainWindow`)
{
deleteUI gearCreatorMainWindow ;
}
// Main Window
window -t "Gear Creator" -rtf 1 gearCreatorMainWindow ;

// Tab Layout creation
// Gear by Gear creation layout

columnLayout -rs 5 -cat "left" 10 ;
//Introduction Info
text -l "Welcome to the Gear Creator: Create a gear set, Select the set, and start creating gears!" ;

// Gear Sets Frame
frameLayout -mw 10 -label "Gear Sets" -labelAlign "top" -borderStyle "out" ;
columnLayout ;
textFieldButtonGrp -l "New Set's Name:" -text "gearSetNameDefault" -bl "Create New Gear Set" -bc "gearSet create" txtFieldNewSet ;
text -l "Changing these sliders will update the selected Gear Set" ;
floatSliderGrp -l "Tooth Width:" -minValue .25 -maxValue 1 -fieldMaxValue 10 -fieldMinValue .01 -s .01 -f 1 -v 0.5 -cc "gearSet rebuild" floatSldrToothWidth ;
floatSliderGrp -l "Tooth Length:" -minValue .1 -maxValue 10 -s .01 -f 1 -v 2 -cc "gearSet rebuild" floatSldrToothLength ;
floatSliderGrp -l "Tooth Bevel Amount:" -minValue 0 -maxValue 1 -s .01 -f 1 -v 0.5 -cc "gearSet rebuild" floatSldrToothBevel ;
floatFieldGrp -l "Rotation Speed:" -nf 1 -v1 50 -cc ("gearSet setRotationSpeed") floatFieldRotationSpeed;
rowLayout -nc 2 -cw2 150 150 ;
button -l "Delete Selected Set" -c "gearSet delete" ;
button -l "Select Set Gear Belongs To" -c "gearSet selectFromGear" ;
setParent .. ;
setParent .. ;
setParent .. ;
setParent .. ;

// Gear by Gear Frame
frameLayout -mw 5 -label "Gear By Gear Creation" -labelAlign "top" -borderStyle "out" -cll 1 ;
rowLayout -nc 2 -cw2 200 200;
columnLayout ;
text -l "Select Gear Type to Create:" ;
radioButtonGrp -vr -nrb 2 -l1 "Spur Gear" -l2 "Face Gear" -sl 1 radioGearType ;
button -l "Create New Gear" -c gearCreateWindow ;
setParent .. ;
columnLayout ;
text -l "Select Gear Material:" ;
text -l "Selected material will also be applied to new Gears" ;
radioButtonGrp -vr -nrb 3 -l1 "Steel" -l2 "Bronze" -l3 "Wood" -sl 1 radioGearMaterial ;
button -l "Assign Gear Material" -c "string $strSelection[] = `ls -tr -sl`; gearMaterial $strSelection[0] UI;" ;
setParent .. ;
setParent .. ;
setParent .. ;
setParent .. ;

// Random Gear Frame
frameLayout -mw 5 -label "Random Gear Creation" -labelAlign "top" -borderStyle "out" -cll 1 ;
rowLayout -nc 2 -cw2 300 300;
columnLayout ;
text -l "Set the probability for each Gear:" ;
text -l " Low High" ;
floatSliderGrp -l "Spur Gear:" -minValue 0 -maxValue 100 -cw 1 80 -f 0 -s .5 -v 50 floatSldrSpurChance ;
floatSliderGrp -l "Face Gear:" -minValue 0 -maxValue 100 -cw 1 80 -f 0 -s .5 -v 50 floatSldrFaceChance ;
text -l "\nSet the probability for each Material:" ;
text -l " Low High" ;
floatSliderGrp -l "Steel:" -minValue 0 -maxValue 100 -cw 1 80 -f 0 -s .5 -v 50 floatSldrSteelChance ;
floatSliderGrp -l "Bronze:" -minValue 0 -maxValue 100 -cw 1 80 -f 0 -s .5 -v 50 floatSldrBronzeChance ;
floatSliderGrp -l "Wood:" -minValue 0 -maxValue 100 -cw 1 80 -f 0 -s .5 -v 50 floatSldrWoodChance ;
setParent .. ;
columnLayout ;
text -l "Set the values for each Gear Characteristic:" ;
text -l "-------Radius:" ;
rowLayout -nc 4 -cw4 50 70 50 70 ;
text -l "Minimum:" ;
floatField -minValue 5 -maxValue 100 -v 5 floatFldRadiusMin ;
text -l "Maximum:" ;
floatField -minValue 10 -maxValue 100 -v 20 floatFldRadiusMax ;
setParent .. ;
text -l "\n-------Height:" ;
rowLayout -nc 4 -cw4 50 70 50 70 ;
text -l "Minimum:" ;
floatField -minValue .25 -maxValue 10 -v 2 floatFldHeightMin ;
text -l "Maximum:" ;
floatField -minValue .25 -maxValue 10 -v 4 floatFldHeightMax ;
setParent .. ;
text -l "\n-------Orientation Angle:" ;
rowLayout -nc 4 -cw4 50 70 50 70 ;
text -l "Minimum:" ;
intField -minValue -90 -maxValue 90 -v -45 intFldAngleMin ;
text -l "Maximum:" ;
intField -minValue -90 -maxValue 90 -v 45 intFldAngleMax ;
setParent .. ;
text -l "\n" ;
intFieldGrp -l "Number of Gears to Create:" -v1 5 intFldNumGears ;
button -l "Create Random Gears" -c "gearSet createRandomGears" ;
setParent .. ;
setParent .. ;
setParent .. ;
setParent .. ;
setParent .. ;
showWindow gearCreatorMainWindow ;
}