# Malcolm Kesson
# 21 October 2012
#
# Workflow
# 1     Create a curve and use mel "rebuildCurve".
# 2     Transform tab, Attribute->RenderMan->Add Custom Shading Group.
# 3  InitialShadingGroup, Attribute->RenderMan->Add Ribbox.
# 4  Ribbox dropdown menu change "None" to "TCL".
# 5  Copy and paste the following command into the Ribbox,
#    don't forget the opening and closing square brackets.
#         [chain $OBJNAME 20 0.5 0.2]
# This will put 20 links along the path of the curve with a link
# width to link length ratio (proportions) of 0.5 and a link 
# thickness of 0.2.
# Revisions:
#   Jan 26 2014 proc now adds links upto a curves max_u value.
proc chain { OBJNAME numchains hr thick} {    
    # In the case of a rebuilt curve u_max will be 1.0, otherwise,
    # is will be a larger value, say, 4.
    set u_max [mel "getAttr $OBJNAME.maxValue"]
    set u_step [expr double($u_max)/($numchains - 0)]    
    
    set rib ""
    set flip 0
    for {set u 0} {$u < $u_max} {set u [expr $u + $u_step] } {
        set next_u [expr $u + $u_step]
        set pnt      [mel "pointOnCurve -pr $u -p $OBJNAME"]
        set next_pnt [mel "pointOnCurve -pr $next_u -p $OBJNAME"]
    
        # Get the transformations to position and orientate a link
        set vec [vector $pnt $next_pnt]
        # The proc "aimY" is implemented in VectorUtils.tcl. Consequently, 
        # VectorUtils.tcl must also be in the same directory as this script.
        set rot [aimY $vec]
        set xrot [lindex $rot 0]
        set zrot [lindex $rot 1]
        set x   [lindex $pnt 0]
        set y   [lindex $pnt 1]
           set z   [lindex $pnt 2]    
        # Link lengths may vary depending on the uniformity of the curve
        set linklen [length $vec]
        
        append rib "AttributeBegin # $u\n"
        append rib "  Identity\n"
        append rib "  Translate $x $y $z\n"
        append rib "  Rotate $zrot 0 0 1\n"
        append rib "  Rotate $xrot 1 0 0\n"
        if {$flip} {
            append rib "  Rotate 90 0 1 0\n"
            set flip 0
        } else {
            set flip 1
            }
        append rib "  [linkgen $linklen $hr $thick]\n"
        append rib "AttributeEnd\n"
        }
    return $rib
    }
  
# This proc is used internally to create a single link constructed
# from two quadric torii and two quadric cylinders.
proc linkgen {L ratio thick} {
    set W [expr $L * $ratio]
    set R [expr double($W) / 2]
    set r [expr double($thick)/2]
    # delta is used to shift the torii to avoid gaps in the chain.
    set delta [expr $R - $r]
    
    # Because the distance between the two torii has been reduced
    # the length of the cylinders must also be reduced.
    set linklen [expr $L - 2.0 * $delta]
    set rib "AttributeBegin\n"
    append rib "    Translate 0 $delta 0\n"
    append rib "    TransformBegin\n"
    append rib "        Rotate 180.0 0 0 1\n"
    append rib "        Torus $R $r 0 360 180.0\n"
    append rib "    TransformEnd\n"
    append rib "    TransformBegin\n"
    append rib "        Translate 0.0 $linklen 0.0\n"
    append rib "        Torus $R $r 0.0 360 180.0\n"
    append rib "    TransformEnd\n"
    append rib "    Rotate -90.0  1 0 0\n"
    append rib "    TransformBegin\n"    
    append rib "        Translate $R 0 0\n"
    append rib "        Cylinder $r 0.0 $linklen  360.0\n"
    append rib "        Translate [expr -2.0 * $R] 0 0\n"
    append rib "        Cylinder $r 0.0 $linklen  360.0\n"
    append rib "    TransformEnd\n"
    append rib "AttributeEnd\n"
    return $rib
    }
::RMS::LogMsg INFO "Custom TCL procs in ChainUtils.tcl loaded"