Difference between revisions of "User:Remig/plico/tug"

From Jmol
Jump to navigation Jump to search
(Do not var globals)
(lc all functions)
Line 7: Line 7:
  
 
Copy and paste the following into a text editor and save in your scripts folder as tug.spt.  
 
Copy and paste the following into a text editor and save in your scripts folder as tug.spt.  
<pre>#   tug - Jmol script by Ron Mignery
+
<pre>#   tug - Jmol script by Ron Mignery
#  v1.10 beta    4/3/2014 for Jmol 14 -do not var globals for Jmol 14.0.13+
+
#  v1.11 beta    5/16/2014 -lc all functions
 
#
 
#
 
#  Translate or rotate a stretch of a polypeptide against itself
 
#  Translate or rotate a stretch of a polypeptide against itself
 
#    or against other chains by mouse actions
 
#    or against other chains by mouse actions
 
#
 
#
kTug = 1
+
kTug = 3
 
gCanchorIdx = -1
 
gCanchorIdx = -1
 
gCanchorNo = -1
 
gCanchorNo = -1
Line 29: Line 29:
 
gCrotors = array()
 
gCrotors = array()
 
gNrotors = array()
 
gNrotors = array()
gMouseX = 0
 
gMouseY = 0
 
 
gOkCollide = ({})
 
gOkCollide = ({})
 
gChain = ""
 
gChain = ""
 
gMinNo = 1
 
gMinNo = 1
 
gMaxNo = 9999
 
gMaxNo = 9999
gScheme = "Jmol"
 
gAltScheme = "Rasmol"
 
 
gCargoSet = ({})
 
gCargoSet = ({})
 
gMovingSet = ({})
 
gMovingSet = ({})
Line 43: Line 39:
 
gSCcircle = -1
 
gSCcircle = -1
 
gSCpt = {0 0 0}
 
gSCpt = {0 0 0}
gOK = TRUE # global return value to work around jmol *feature*
 
gOk2 = TRUE # "    "
 
 
gTargetPt = {0 0 0}
 
gTargetPt = {0 0 0}
 
gNewDrag = FALSE
 
gNewDrag = FALSE
Line 57: Line 51:
  
  
function getCAmNo (iNo) {
+
function get_cam_no (iNo) {
 
     while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) {
 
     while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) {
 
         iNo--
 
         iNo--
Line 64: Line 58:
 
}
 
}
  
function getCAmIdx (idx) {
+
function get_cam_idx (idx) {
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
     no = getCAmNo( no)
+
     no = get_cam_no( no)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
}
 
}
  
function getCApNo (iNo) {
+
function get_cap_no (iNo) {
 
     while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) {
 
     while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) {
 
         iNo++
 
         iNo++
Line 77: Line 71:
 
}
 
}
  
function getCpIdx (idx) {
+
function getCApIdx (idx) {
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
     no = getCpNo( no)
+
     no = get_cap_no( no)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
}
 
}
  
function getCpNo (iNo) {
+
function get_cp_no (iNo) {
 
     while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) {
 
     while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) {
 
         iNo++
 
         iNo++
Line 90: Line 84:
 
}
 
}
  
function getCApIdx (idx) {
+
function get_cp_idx (idx) {
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
     no = getCApNo( no)
+
     no = get_cp_no( no)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
}
 
}
  
function getCmNo (iNo) {
+
function get_cm_no (iNo) {
 
     while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) {
 
     while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) {
 
         iNo--
 
         iNo--
Line 103: Line 97:
 
}
 
}
  
function getCmIdx (idx) {
+
function get_cm_idx (idx) {
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
     no = getCmNo( no)
+
     no = get_cm_no( no)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
}
 
}
  
function getNmNo (iNo) {
+
function get_nm_no (iNo) {
 
     while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) {
 
     while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) {
 
         iNo--
 
         iNo--
Line 116: Line 110:
 
}
 
}
  
function getNmIdx (idx) {
+
function get_nm_idx (idx) {
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
 
     var no = {atomIndex=idx and (chain=gChain)}.atomno
     no = getNmNo( no)
+
     no = get_nm_no( no)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
}
 
}
  
function getNpNo (iNo) {
+
function get_np_no (iNo) {
 
     while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) {
 
     while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) {
 
         iNo++
 
         iNo++
Line 129: Line 123:
 
}
 
}
  
function getNpIdx (idx) {
+
function get_np_idx (idx) {
 
     var no = {atomIndex=idx}.atomno
 
     var no = {atomIndex=idx}.atomno
     no = getNpNo( no)
+
     no = get_np_no( no)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
     return ({(atomno=no) and (chain=gChain)}.atomIndex)
 
}
 
}
  
function getCBidx (BBidx) {
+
function get_cb_idx (BBidx) {
 
     var no = {atomIndex=BBidx}.atomno
 
     var no = {atomIndex=BBidx}.atomno
 
     var i = 1
 
     var i = 1
Line 146: Line 140:
 
}
 
}
  
function getOidx (BBidx) {
+
function get_o_idx (BBidx) {
 
     var no = {atomIndex=BBidx}.atomno
 
     var no = {atomIndex=BBidx}.atomno
 
     var i = 1
 
     var i = 1
Line 157: Line 151:
 
}
 
}
  
function getNwardBBno (iNo, iChain) {
+
function get_nward_bb_no (iNo, iChain) {
 
     while ((iNo >= 0) and (
 
     while ((iNo >= 0) and (
 
         ({(atomno=iNo) and (chain=iChain)}.atomName != "N")
 
         ({(atomno=iNo) and (chain=iChain)}.atomName != "N")
Line 167: Line 161:
 
}
 
}
  
function getNwardBBidx (idx, iChain) {
+
function get_nward_bb_idx (idx, iChain) {
 
     var no = {atomIndex=idx}.atomno - 1
 
     var no = {atomIndex=idx}.atomno - 1
     no = getNwardBBno( no, iChain)
+
     no = get_nward_bb_no( no, iChain)
 
     return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1)
 
     return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1)
 
}
 
}
  
function getCwardBBno (iNo, iChain) {
+
function get_cward_bb_no (iNo, iChain) {
 
     while ((iNo < gMaxNo) and (
 
     while ((iNo < gMaxNo) and (
 
         ({(atomno=iNo) and (chain=iChain)}.atomName != "N")
 
         ({(atomno=iNo) and (chain=iChain)}.atomName != "N")
Line 183: Line 177:
 
}
 
}
  
function getCwardBBidx (idx, iChain) {
+
function get_cward_bb_idx (idx, iChain) {
 
     var no = {atomIndex=idx}.atomno + 1
 
     var no = {atomIndex=idx}.atomno + 1
     no = getCwardBBno( no, iChain)
+
     no = get_cward_bb_no( no, iChain)
 
     return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1)
 
     return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1)
 
}
 
}
  
function getScSet (scIdx, iChain) {
+
function get_sc_set (scIdx, iChain) {
 
     var scSet = ({})
 
     var scSet = ({})
     var idx = getScBBidx(scIdx, iChain)
+
     var idx = get_sc_bb_idx(scIdx, iChain)
 
     var iNo = {atomIndex=idx}.atomno + 3
 
     var iNo = {atomIndex=idx}.atomno + 3
 
      
 
      
 
     for (var i = 1; i < 20; i++) {
 
     for (var i = 1; i < 20; i++) {
 
         idx = {(atomno=@{iNo+i}) and (chain=iChain)}.atomIndex
 
         idx = {(atomno=@{iNo+i}) and (chain=iChain)}.atomIndex
         if (isBBidx(idx)) {
+
         if (is_bb_idx(idx)) {
 
             break
 
             break
 
         }
 
         }
Line 204: Line 198:
 
}
 
}
  
function getScBBidx (idx, iChain) {
+
function get_sc_bb_idx (idx, iChain) {
 
     var no = {atomIndex=idx}.atomno
 
     var no = {atomIndex=idx}.atomno
 
     for (; no > 0; no--) {
 
     for (; no > 0; no--) {
Line 224: Line 218:
 
}
 
}
  
function isBBidx(aIdx) {
+
function is_bb_idx(aIdx) {
 
     var ret = FALSE
 
     var ret = FALSE
 
     switch({atomIndex=aIdx}.atomName) {
 
     switch({atomIndex=aIdx}.atomName) {
Line 236: Line 230:
 
}
 
}
  
function isSCidx(aIdx) {
+
function is_sc_idx(aIdx) {
  
 
     var ret = FALSE
 
     var ret = FALSE
     if (not isBBidx(aIDx)) {
+
     if (not is_bb_idx(aIDx)) {
  
 
         ret = TRUE
 
         ret = TRUE
Line 252: Line 246:
 
}
 
}
  
function addSideChainToSelection(CAno, isAdd, addOXT, iChain) {
+
function add_sc_to_select(CAno, isAdd, addOXT, iChain) {
 
     var iNo = CAno+3
 
     var iNo = CAno+3
 
     while ({(atomno=iNo) and (chain=iChain)}.resno == {(atomno=CAno) and (chain=iChain)}.resno) {
 
     while ({(atomno=iNo) and (chain=iChain)}.resno == {(atomno=CAno) and (chain=iChain)}.resno) {
Line 263: Line 257:
 
}
 
}
  
function selectAddSideChain(fromIdx) {
+
function select_add_sc(fromIdx) {
 
     var iNo = {atomIndex=fromIdx}.atomno
 
     var iNo = {atomIndex=fromIdx}.atomno
 
     var iChain = {atomIndex=fromIdx}.chain
 
     var iChain = {atomIndex=fromIdx}.chain
Line 278: Line 272:
 
# First and last are BB atoms
 
# First and last are BB atoms
 
# Any side atoms in the range are also selected
 
# Any side atoms in the range are also selected
function selectNwardIdx (firstIdx, lastIdx) {
+
function select_nward_idx (firstIdx, lastIdx) {
 
     var firstno = ((firstIdx < 0) ? {atomIndex=lastIdx}.atomno : {atomIndex=firstIdx}.atomno)
 
     var firstno = ((firstIdx < 0) ? {atomIndex=lastIdx}.atomno : {atomIndex=firstIdx}.atomno)
 
     var lastno = ((lastIdx < 0) ? firstno : {atomIndex=lastIdx}.atomno)
 
     var lastno = ((lastIdx < 0) ? firstno : {atomIndex=lastIdx}.atomno)
Line 287: Line 281:
  
 
     if ({(atomno=firstno) and (chain=gChain)}.atomName == "C") { # if psi
 
     if ({(atomno=firstno) and (chain=gChain)}.atomName == "C") { # if psi
         addSideChainToSelection(firstno-1, TRUE, TRUE, iChain)
+
         add_sc_to_select(firstno-1, TRUE, TRUE, iChain)
 
         {(atomno=@{firstno+1}) and (chain=iChain)}.selected = TRUE # add O
 
         {(atomno=@{firstno+1}) and (chain=iChain)}.selected = TRUE # add O
 
     }
 
     }
 
     if ({(atomno=firstno) and (chain=iChain)}.atomName == "CA") {
 
     if ({(atomno=firstno) and (chain=iChain)}.atomName == "CA") {
         addSideChainToSelection(firstno, TRUE, FALSE, iChain)
+
         add_sc_to_select(firstno, TRUE, FALSE, iChain)
 
     }
 
     }
 
     if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi
 
     if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi
         addSideChainToSelection(lastno-1, FALSE, FALSE, iChain)
+
         add_sc_to_select(lastno-1, FALSE, FALSE, iChain)
 
     }
 
     }
 
}
 
}
Line 300: Line 294:
 
# First and last are BB atoms
 
# First and last are BB atoms
 
# Any side atoms in the range are also selected
 
# Any side atoms in the range are also selected
function selectCwardIdx (firstIdx, lastIdx) {
+
function select_cward_idx (firstIdx, lastIdx) {
 
     var firstno = ((firstIdx < 0) ? gMaxNo : {atomIndex=firstIdx}.atomno)
 
     var firstno = ((firstIdx < 0) ? gMaxNo : {atomIndex=firstIdx}.atomno)
 
     var lastno = ((lastIdx < 0) ? 1 : {atomIndex=lastIdx}.atomno)
 
     var lastno = ((lastIdx < 0) ? 1 : {atomIndex=lastIdx}.atomno)
Line 325: Line 319:
  
 
     if ({(atomno=firstno) and (chain=iChain)}.atomName == "C") { # if psi
 
     if ({(atomno=firstno) and (chain=iChain)}.atomName == "C") { # if psi
         addSideChainToSelection(firstno-1, FALSE, FALSE, iChain)
+
         add_sc_to_select(firstno-1, FALSE, FALSE, iChain)
 
     }
 
     }
 
     if ({(atomno=lastno) and (chain=iChain)}.atomName == "CA") {
 
     if ({(atomno=lastno) and (chain=iChain)}.atomName == "CA") {
         addSideChainToSelection(lastno, TRUE, FALSE, iChain)
+
         add_sc_to_select(lastno, TRUE, FALSE, iChain)
 
     }
 
     }
 
     if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi
 
     if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi
         addSideChainToSelection(lastno-1, TRUE, TRUE, iChain)
+
         add_sc_to_select(lastno-1, TRUE, TRUE, iChain)
 
         {(atomno=@{lastno+1}) and (chain=iChain)}.selected = TRUE # add O
 
         {(atomno=@{lastno+1}) and (chain=iChain)}.selected = TRUE # add O
 
     }
 
     }
Line 338: Line 332:
  
 
# Resolve collisions
 
# Resolve collisions
function handleCollisions2( targetIdx) {
+
function handle_collisions_2( targetIdx) {
  
 
     # For all selected atoms
 
     # For all selected atoms
Line 353: Line 347:
  
 
                 # Ignore kinked BB
 
                 # Ignore kinked BB
                 if (isBBidx(idx) and angle({atomIndex=@{getCwardBBidx(idx, gChain)}},
+
                 if (is_bb_idx(idx) and angle({atomIndex=@{get_cward_bb_idx(idx, gChain)}},
                     {atomIndex=idx} , {atomIndex=@{getNwardBBidx(idx, gChain)}}) < 100) {
+
                     {atomIndex=idx} , {atomIndex=@{get_nward_bb_idx(idx, gChain)}}) < 100) {
 
                     continue
 
                     continue
 
                 }
 
                 }
Line 368: Line 362:
  
 
                     # else if it is with side chain not proline, fix it
 
                     # else if it is with side chain not proline, fix it
                     else if (isSCidx(cidx) and ({atomIndex=cidx}.group != "PRO")) {
+
                     else if (is_sc_idx(cidx) and ({atomIndex=cidx}.group != "PRO")) {
                         fixSCcollision2(cidx)
+
                         fix_sc_collision_2(cidx)
 
                         recollect = TRUE
 
                         recollect = TRUE
  
Line 379: Line 373:
  
 
                     # else if it is itself a side chain not proline, fix it
 
                     # else if it is itself a side chain not proline, fix it
                     else if (isSCidx(idx) and ({atomIndex=idx}.group != "PRO")) {
+
                     else if (is_sc_idx(idx) and ({atomIndex=idx}.group != "PRO")) {
                         fixSCcollision2(idx)
+
                         fix_sc_collision_2(idx)
 
                         recollect = TRUE
 
                         recollect = TRUE
  
Line 391: Line 385:
 
                     # Else if it is with O, counter-rotate
 
                     # Else if it is with O, counter-rotate
 
                     else if (lcAtoms[c].atomName = "O") {
 
                     else if (lcAtoms[c].atomName = "O") {
                         counterRotate2(lcAtoms[c].atomIndex,
+
                         counter_rotate_2(lcAtoms[c].atomIndex,
 
                             {atomIndex=idx}.xyz, targetIdx, FALSE)
 
                             {atomIndex=idx}.xyz, targetIdx, FALSE)
  
Line 402: Line 396:
 
                     # Else if it is itself O, counter-rotate
 
                     # Else if it is itself O, counter-rotate
 
                     else if ({atomIndex=idx}.atomName = "O") {
 
                     else if ({atomIndex=idx}.atomName = "O") {
                         counterRotate2(idx, lcAtoms[c].xyz, targetIdx, FALSE)
+
                         counter_rotate_2(idx, lcAtoms[c].xyz, targetIdx, FALSE)
  
 
                         # If not fixed, exit fail
 
                         # If not fixed, exit fail
Line 421: Line 415:
  
 
# Rotate rotor set to move target atom to its proper place
 
# Rotate rotor set to move target atom to its proper place
function tugTrackIdx(targetIdx, targetPt, nWard, cDetect) {
+
function tug_track_idx(targetIdx, targetPt, nWard, cDetect) {
 
     gOK = FALSE
 
     gOK = FALSE
 
     var pt = targetPt
 
     var pt = targetPt
Line 478: Line 472:
 
             if (nWard) {
 
             if (nWard) {
 
                 if ({atomIndex=i2}.atomName="CA") {
 
                 if ({atomIndex=i2}.atomName="CA") {
                     psi = angle({atomIndex=@{getCwardBBidx(i1, gChain)}}, {atomIndex=i1},
+
                     psi = angle({atomIndex=@{get_cward_bb_idx(i1, gChain)}}, {atomIndex=i1},
 
                         {atomIndex=i2}, {atomIndex=i3}) + dt
 
                         {atomIndex=i2}, {atomIndex=i3}) + dt
 
                 }
 
                 }
 
                 else {
 
                 else {
 
                     phi = angle({atomIndex=i1}, {atomIndex=i2},
 
                     phi = angle({atomIndex=i1}, {atomIndex=i2},
                         {atomIndex=i3}, {atomIndex=@{getNwardBBidx(i3, gChain)}}) + dt
+
                         {atomIndex=i3}, {atomIndex=@{get_nward_bb_idx(i3, gChain)}}) + dt
 
                 }
 
                 }
  
 
                 if ({atomIndex=i2}.atomno > {atomIndex=targetIdx}.atomno) {
 
                 if ({atomIndex=i2}.atomno > {atomIndex=targetIdx}.atomno) {
 
                     movePt = TRUE
 
                     movePt = TRUE
                     selectNwardIdx(i3, getCwardBBidx(targetIdx, gChain))
+
                     select_nward_idx(i3, get_cward_bb_idx(targetIdx, gChain))
 
                     {atomIndex=targetIdx}.selected = TRUE
 
                     {atomIndex=targetIdx}.selected = TRUE
 
                 }
 
                 }
 
                 else {
 
                 else {
                     selectCwardIdx(i2, targetIdx)
+
                     select_cward_idx(i2, targetIdx)
 
                 }
 
                 }
 
             }
 
             }
 
             else {
 
             else {
 
                 if (({atomIndex=i2}.atomName="CA")) {
 
                 if (({atomIndex=i2}.atomName="CA")) {
                     phi = angle({atomIndex=@{getNwardBBidx(i1, gChain)}}, {atomIndex=i1},
+
                     phi = angle({atomIndex=@{get_nward_bb_idx(i1, gChain)}}, {atomIndex=i1},
 
                         {atomIndex=i2}, {atomIndex=i3}) + dt
 
                         {atomIndex=i2}, {atomIndex=i3}) + dt
 
                 }
 
                 }
 
                 else {
 
                 else {
 
                     psi = angle({atomIndex=i2}, {atomIndex=i3},
 
                     psi = angle({atomIndex=i2}, {atomIndex=i3},
                         {atomIndex=i4}, {atomIndex=@{getCwardBBidx(i4, gChain)}}) + dt
+
                         {atomIndex=i4}, {atomIndex=@{get_cward_bb_idx(i4, gChain)}}) + dt
 
                 }
 
                 }
  
 
                 if ({atomIndex=i2}.atomno < {atomIndex=targetIdx}.atomno) {
 
                 if ({atomIndex=i2}.atomno < {atomIndex=targetIdx}.atomno) {
 
                     movePt = TRUE
 
                     movePt = TRUE
                     selectCwardIdx(i3, getNwardBBidx(targetIdx, gChain))
+
                     select_cward_idx(i3, get_nward_bb_idx(targetIdx, gChain))
 
                     {atomIndex=targetIdx}.selected = TRUE
 
                     {atomIndex=targetIdx}.selected = TRUE
 
                 }
 
                 }
 
                 else {
 
                 else {
                     selectNwardIdx(i2, targetIdx)
+
                     select_nward_idx(i2, targetIdx)
 
                 }
 
                 }
 
             }
 
             }
Line 543: Line 537:
 
                             dt /= 2
 
                             dt /= 2
 
                         }
 
                         }
                         handleCollisions2( targetIdx)
+
                         handle_collisions_2( targetIdx)
 
                         if (not gOk2) {
 
                         if (not gOk2) {
 
                             wasCollision = TRUE
 
                             wasCollision = TRUE
Line 590: Line 584:
  
 
# Counter rotate bonds on either side of a BB O
 
# Counter rotate bonds on either side of a BB O
function docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nWard) {
+
function do_counter_rotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nWard) {
  
 
     # Rotate psi
 
     # Rotate psi
Line 605: Line 599:
 
}
 
}
  
function counterRotate(oIdx, dir, nWard) {
+
function counter_rotate(oIdx, dir, nWard) {
  
 
     var iChain = {atomIndex=oIdx}.chain
 
     var iChain = {atomIndex=oIdx}.chain
 
     var selsave = {selected}
 
     var selsave = {selected}
     var cIdx = getScBBidx(oIdx, iChain)
+
     var cIdx = get_sc_bb_idx(oIdx, iChain)
     var nIdx = getCwardBBidx(cIdx, iChain)
+
     var nIdx = get_cward_bb_idx(cIdx, iChain)
     var caPhiIdx = getCwardBBidx(nIdx, iChain)
+
     var caPhiIdx = get_cward_bb_idx(nIdx, iChain)
     var caPsiIdx = getNwardBBidx(cIdx, iChain)
+
     var caPsiIdx = get_nward_bb_idx(cIdx, iChain)
  
 
     if (nWard) {
 
     if (nWard) {
 
         nNo = {chain=iChain}.atomno.min
 
         nNo = {chain=iChain}.atomno.min
         selectNwardIdx(caPsiIdx, {(atomno=nNo) and (chain=iChain)}.atomIndex)
+
         select_nward_idx(caPsiIdx, {(atomno=nNo) and (chain=iChain)}.atomIndex)
 
     }
 
     }
 
     else {
 
     else {
 
         cNo = {chain=iChain}.atomno.max
 
         cNo = {chain=iChain}.atomno.max
         selectCwardIdx(caPhiIdx, {(atomno=cNo) and (chain=iChain)}.atomIndex)
+
         select_cward_idx(caPhiIdx, {(atomno=cNo) and (chain=iChain)}.atomIndex)
 
     }
 
     }
  
 
     # Counter-rotate
 
     # Counter-rotate
     docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, not nWard)
+
     do_counter_rotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, not nWard)
 
     select selsave
 
     select selsave
 
}
 
}
  
function counterRotate2(oIdx, toPt, terminalIdx, oDrag) {
+
function counter_rotate_2(oIdx, toPt, terminalIdx, oDrag) {
  
 
     var iChain = {atomIndex=oIdx}.chain
 
     var iChain = {atomIndex=oIdx}.chain
 
     var selsave = {selected}
 
     var selsave = {selected}
 
     var gOk2 = TRUE
 
     var gOk2 = TRUE
     var cIdx = getScBBidx(oIdx, iChain)
+
     var cIdx = get_sc_bb_idx(oIdx, iChain)
     var nIdx = getCwardBBidx(cIdx, iChain)
+
     var nIdx = get_cward_bb_idx(cIdx, iChain)
     var caPhiIdx = getCwardBBidx(nIdx, iChain)
+
     var caPhiIdx = get_cward_bb_idx(nIdx, iChain)
     var caPsiIdx = getNwardBBidx(cIdx, iChain)
+
     var caPsiIdx = get_nward_bb_idx(cIdx, iChain)
  
 
     var nTward = ({atomIndex=oIdx}.atomno < {atomIndex=terminalIdx}.atomno)
 
     var nTward = ({atomIndex=oIdx}.atomno < {atomIndex=terminalIdx}.atomno)
 
     if (nTward) {
 
     if (nTward) {
         selectCwardIdx(cIdx, terminalIdx)
+
         select_cward_idx(cIdx, terminalIdx)
 
     }
 
     }
 
     else {
 
     else {
         selectNwardIdx(nIdx, terminalIdx)
+
         select_nward_idx(nIdx, terminalIdx)
 
     }
 
     }
  
Line 655: Line 649:
  
 
         # Counter-rotate
 
         # Counter-rotate
         docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nTward)
+
         do_counter_rotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nTward)
 
         var newang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx})
 
         var newang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx})
  
 
         # If wrong direction once, undo and reverse
 
         # If wrong direction once, undo and reverse
 
         if (newang > ang) {
 
         if (newang > ang) {
             docounterRotate(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, -dir, nTward)
+
             do_counter_rotate(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, -dir, nTward)
  
 
             # If first time, continue in opposite direction
 
             # If first time, continue in opposite direction
Line 685: Line 679:
  
 
# Repair proline
 
# Repair proline
function repairProline(BBidx) {
+
function repair_proline(BBidx) {
     var cbidx = getCBidx(BBidx)
+
     var cbidx = get_cb_idx(BBidx)
 
     var cbno = {atomIndex=cbidx}.atomno
 
     var cbno = {atomIndex=cbidx}.atomno
 
     var cgidx = {(atomno=@{cbno+1}) and (chain=gChain)}.atomIndex
 
     var cgidx = {(atomno=@{cbno+1}) and (chain=gChain)}.atomIndex
Line 694: Line 688:
  
 
     select {atomIndex=cbidx}
 
     select {atomIndex=cbidx}
     setAngleIdx(nidx, caidx, cbidx, 109.5)
+
     set_angle_idx(nidx, caidx, cbidx, 109.5)
  
 
     select {atomIndex=cdidx}
 
     select {atomIndex=cdidx}
     setDistanceIdx(nidx, cdidx, 1.47)
+
     set_distance_idx(nidx, cdidx, 1.47)
     setAngleIdx(caidx, nidx, cdidx, 102.7)
+
     set_angle_idx(caidx, nidx, cdidx, 102.7)
     setDihedralIdx(cbidx, caidx, nidx, cdidx, 16.2)
+
     set_dihedral_idx(cbidx, caidx, nidx, cdidx, 16.2)
  
 
     select {atomIndex=cgidx}
 
     select {atomIndex=cgidx}
     setDistanceIdx(cdidx, cgidx, 1.51)
+
     set_distance_idx(cdidx, cgidx, 1.51)
     setAngleIdx(nidx, cdidx, cgidx, 106.4)
+
     set_angle_idx(nidx, cdidx, cgidx, 106.4)
     setDihedralIdx(caidx, nidx, cdidx, cgidx, 16.2)
+
     set_dihedral_idx(caidx, nidx, cdidx, cgidx, 16.2)
 
}
 
}
  
 
# Repair side chain
 
# Repair side chain
function repairSideChain(targetIdx, nWard) {
+
function repair_sc(targetIdx, nWard) {
  
     var idx = (nWard ? getCwardBBidx(targetIdx, gChain) : getNwardBBidx(targetIdx, gChain))
+
     var idx = (nWard ? get_cward_bb_idx(targetIdx, gChain) : get_nward_bb_idx(targetIdx, gChain))
  
 
     if (({atomIndex=targetIdx}.atomName == "CA")
 
     if (({atomIndex=targetIdx}.atomName == "CA")
 
         and ({atomIndex=targetIdx}.group != "GLY")) {
 
         and ({atomIndex=targetIdx}.group != "GLY")) {
         var cbidx = getCBidx(targetIdx)
+
         var cbidx = get_cb_idx(targetIdx)
 
         select none
 
         select none
         selectAddSideChain(cbidx)
+
         select_add_sc(cbidx)
         setAngleIdx(idx, targetIdx, cbidx, 110.0)
+
         set_angle_idx(idx, targetIdx, cbidx, 110.0)
         setDistanceIdx(targetIdx, cbidx, 1.5)
+
         set_distance_idx(targetIdx, cbidx, 1.5)
 
         if ({atomIndex=targetIdx}.group != "PRO") {
 
         if ({atomIndex=targetIdx}.group != "PRO") {
 
             var colliders = (within(kCtolerance, FALSE, {selected})
 
             var colliders = (within(kCtolerance, FALSE, {selected})
Line 724: Line 718:
 
             if (colliders.size > 0) {
 
             if (colliders.size > 0) {
 
                 if ({atomIndex=targetIdx}.group != "ALA") {
 
                 if ({atomIndex=targetIdx}.group != "ALA") {
                     fixSCcollision2(cbidx)
+
                     fix_sc_collision_2(cbidx)
 
                 }
 
                 }
 
             }
 
             }
Line 732: Line 726:
 
             }
 
             }
 
             else {
 
             else {
                 setDihedralIdx(getNwardBBidx(idx, gChain), idx, targetIdx, cbidx, 174.2)
+
                 set_dihedral_idx(get_nward_bb_idx(idx, gChain), idx, targetIdx, cbidx, 174.2)
 
             }
 
             }
 
         }
 
         }
Line 738: Line 732:
  
 
     else if ({atomIndex=targetIdx}.atomName == "C") {
 
     else if ({atomIndex=targetIdx}.atomName == "C") {
         var oidx = getOidx(targetIdx)
+
         var oidx = get_o_idx(targetIdx)
 
         select {atomIndex=oidx}
 
         select {atomIndex=oidx}
         setAngleIdx(idx, targetIdx, oidx, 120.0)
+
         set_angle_idx(idx, targetIdx, oidx, 120.0)
         setDistanceIdx(targetIdx, oidx, 1.21)
+
         set_distance_idx(targetIdx, oidx, 1.21)
 
         if (nWard) {
 
         if (nWard) {
             setDihedralIdx(getCwardBBidx(idx, gChain), idx, targetIdx, oidx, 0.0)
+
             set_dihedral_idx(get_cward_bb_idx(idx, gChain), idx, targetIdx, oidx, 0.0)
 
         }
 
         }
 
         if ({atomIndex=idx}.group == "PRO") {
 
         if ({atomIndex=idx}.group == "PRO") {
             repairProline(idx)
+
             repair_proline(idx)
 
             var dNo = {atomIndex=targetIdx}.atomno + 4
 
             var dNo = {atomIndex=targetIdx}.atomno + 4
 
             var dIdx = {(atomno=dNO) and (chain=gChain)}.atomIndex
 
             var dIdx = {(atomno=dNO) and (chain=gChain)}.atomIndex
Line 754: Line 748:
 
             for (var i = 1; i <= colliders.size; i++) {
 
             for (var i = 1; i <= colliders.size; i++) {
 
                 if (colliders[i].atomName == "O") {
 
                 if (colliders[i].atomName == "O") {
                     counterRotate2(colliders[i].atomIndex,
+
                     counter_rotate_2(colliders[i].atomIndex,
 
                         {atomIndex=dIdx}.xyz, targetIdx, FALSE)
 
                         {atomIndex=dIdx}.xyz, targetIdx, FALSE)
 
                 }
 
                 }
Line 763: Line 757:
  
 
# Rebuild Cward rotors set
 
# Rebuild Cward rotors set
function tugTrackC() {
+
function tug_track_c() {
  
 
     # For all bb atoms cWard of cargo
 
     # For all bb atoms cWard of cargo
Line 775: Line 769:
  
 
         # Step to next atom
 
         # Step to next atom
         targetIdx = getCwardBBidx(targetIdx, gChain)
+
         targetIdx = get_cward_bb_idx(targetIdx, gChain)
  
 
         # No collision with cargo allowed after two atoms placed
 
         # No collision with cargo allowed after two atoms placed
Line 784: Line 778:
  
 
         # Compute targets desired coords
 
         # Compute targets desired coords
         var c1idx = getCwardBBidx(targetIdx, gChain)
+
         var c1idx = get_cward_bb_idx(targetIdx, gChain)
         var n1idx = getNwardBBidx(targetIdx, gChain )
+
         var n1idx = get_nward_bb_idx(targetIdx, gChain )
         var n2idx = getNwardBBidx(n1Idx, gChain)
+
         var n2idx = get_nward_bb_idx(n1Idx, gChain)
         var n3idx = getNwardBBidx(n2Idx, gChain)
+
         var n3idx = get_nward_bb_idx(n2Idx, gChain)
 
         var pt = {0 0 0}
 
         var pt = {0 0 0}
 
         if ({atomIndex=targetIdx}.atomName == "N") {
 
         if ({atomIndex=targetIdx}.atomName == "N") {
             var oidx = getOidx(n1idx)
+
             var oidx = get_o_idx(n1idx)
 
             select {atomIndex=oidx}
 
             select {atomIndex=oidx}
  
 
             # Desired target location is trigonal O
 
             # Desired target location is trigonal O
             setDistanceIdx(n1idx, oidx, 1.5)
+
             set_distance_idx(n1idx, oidx, 1.5)
             pt = getTrigonalIdx(n2idx, n1idx, oidx, 1.37)
+
             pt = get_trigonal_idx(n2idx, n1idx, oidx, 1.37)
             setDistanceIdx(n1idx, oidx, 1.21)
+
             set_distance_idx(n1idx, oidx, 1.21)
 
         }
 
         }
 
         else if (({atomIndex=targetIdx}.atomName == "C")
 
         else if (({atomIndex=targetIdx}.atomName == "C")
Line 802: Line 796:
  
 
             # Desired target location is tetragonal CB
 
             # Desired target location is tetragonal CB
             var cbidx = getCBidx(n1idx)
+
             var cbidx = get_cb_idx(n1idx)
             pt = getTetIdx(n2idx, n1idx, cbidx, 1.5)
+
             pt = get_tet_idx(n2idx, n1idx, cbidx, 1.5)
 
         }
 
         }
 
         else { # CA (or GLY C)
 
         else { # CA (or GLY C)
Line 812: Line 806:
 
             # Set target atom at desired distance and angle
 
             # Set target atom at desired distance and angle
 
             select {atomIndex=targetIdx}
 
             select {atomIndex=targetIdx}
             setDistanceIdx(n1idx, targetIdx, 1.5)
+
             set_distance_idx(n1idx, targetIdx, 1.5)
             setAngleIdx(n2idx, n1idx, targetIdx, 120.0)
+
             set_angle_idx(n2idx, n1idx, targetIdx, 120.0)
 
             if ({atomIndex=targetIdx}.atomName == "CA") {
 
             if ({atomIndex=targetIdx}.atomName == "CA") {
                 setDihedralIdx(n3idx, n2idx, n1idx, targetIdx, 180)
+
                 set_dihedral_idx(n3idx, n2idx, n1idx, targetIdx, 180)
 
             }
 
             }
  
Line 832: Line 826:
  
 
                 # Rotate on cWard rotor set to move it there
 
                 # Rotate on cWard rotor set to move it there
                 tugTrackIdx(targetIdx, pt, FALSE, FALSE)
+
                 tug_track_idx(targetIdx, pt, FALSE, FALSE)
 
                 xcount++
 
                 xcount++
 
             }
 
             }
Line 845: Line 839:
  
 
             # Adust any side atoms
 
             # Adust any side atoms
             repairSideChain(targetIdx, FALSE)
+
             repair_sc(targetIdx, FALSE)
 
         }
 
         }
  
Line 861: Line 855:
  
 
# Rebuild Nward rotors set
 
# Rebuild Nward rotors set
function tugTrackN() {
+
function tug_track_n() {
  
 
     gOK = TRUE
 
     gOK = TRUE
Line 875: Line 869:
  
 
         # Step to next atom
 
         # Step to next atom
         targetIdx = getNwardBBidx(targetIdx, gChain)
+
         targetIdx = get_nward_bb_idx(targetIdx, gChain)
  
 
         # No collision with cargo allowed after two atoms placed
 
         # No collision with cargo allowed after two atoms placed
Line 884: Line 878:
  
 
         # Compute targets desired coords
 
         # Compute targets desired coords
         var n1idx = getNwardBBidx(targetIdx, gChain)
+
         var n1idx = get_nward_bb_idx(targetIdx, gChain)
         var c1idx = getCwardBBidx(targetIdx, gChain)
+
         var c1idx = get_cward_bb_idx(targetIdx, gChain)
         var c2idx = getCwardBBidx(c1idx, gChain)
+
         var c2idx = get_cward_bb_idx(c1idx, gChain)
         var c3idx = getCwardBBidx(c2idx, gChain)
+
         var c3idx = get_cward_bb_idx(c2idx, gChain)
 
         var pt = {0 0 0}
 
         var pt = {0 0 0}
 
         if ({atomIndex=targetIdx}.atomName == "CA") {
 
         if ({atomIndex=targetIdx}.atomName == "CA") {
  
 
             # Desired target location is trigonal O
 
             # Desired target location is trigonal O
             var oidx = getOidx(c1idx)
+
             var oidx = get_o_idx(c1idx)
 
             select {atomIndex=oidx}
 
             select {atomIndex=oidx}
             setDistanceIdx(c1idx, oidx, 1.39)
+
             set_distance_idx(c1idx, oidx, 1.39)
             pt = getTrigonalIdx(c2idx, c1idx, oidx, 1.41)
+
             pt = get_trigonal_idx(c2idx, c1idx, oidx, 1.41)
             setDistanceIdx(c1idx, oidx, 1.21)
+
             set_distance_idx(c1idx, oidx, 1.21)
 
         }
 
         }
 
         else if (({atomIndex=targetIdx}.atomName == "N")
 
         else if (({atomIndex=targetIdx}.atomName == "N")
Line 902: Line 896:
  
 
             # Desired target location is r-tetragonal CB
 
             # Desired target location is r-tetragonal CB
             var cbidx = getCBidx(c1idx)
+
             var cbidx = get_cb_idx(c1idx)
             pt = getTetIdx(cbidx, c1idx, c2idx, 1.5)
+
             pt = get_tet_idx(cbidx, c1idx, c2idx, 1.5)
 
         }
 
         }
 
         else { # C
 
         else { # C
Line 912: Line 906:
 
             # Set target atom at desired distance and angle
 
             # Set target atom at desired distance and angle
 
             select {atomIndex=targetIdx}
 
             select {atomIndex=targetIdx}
             setDistanceIdx(c1idx, targetIdx, 1.37)
+
             set_distance_idx(c1idx, targetIdx, 1.37)
             setAngleIdx(c2idx, c1idx, targetIdx, 110.0)
+
             set_angle_idx(c2idx, c1idx, targetIdx, 110.0)
  
 
             if ({atomIndex=targetIdx}.group == "PRO") {
 
             if ({atomIndex=targetIdx}.group == "PRO") {
                 setDihedralIdx(c3idx, c2idx, c1idx, targetIdx, -57.0)
+
                 set_dihedral_idx(c3idx, c2idx, c1idx, targetIdx, -57.0)
 
             }
 
             }
  
Line 933: Line 927:
  
 
                 # Rotate on nWard rotor set to move it there
 
                 # Rotate on nWard rotor set to move it there
                 tugTrackIdx(targetIdx, pt, TRUE, FALSE)
+
                 tug_track_idx(targetIdx, pt, TRUE, FALSE)
 
                 xcount++
 
                 xcount++
 
             }
 
             }
Line 946: Line 940:
  
 
             # Adust any side atoms
 
             # Adust any side atoms
             repairSideChain(targetIdx, TRUE)
+
             repair_sc(targetIdx, TRUE)
 
         }
 
         }
  
Line 963: Line 957:
  
 
# gPlicoRecord is maintained by the macro pilcoRecord
 
# gPlicoRecord is maintained by the macro pilcoRecord
function plicoRecord(s) {
+
function plico_record(s) {
 
     var g = format("show file \"%s\"", gPlicoRecord)
 
     var g = format("show file \"%s\"", gPlicoRecord)
 
     var ls = script(g)
 
     var ls = script(g)
Line 974: Line 968:
  
 
# gPlicoRecord is maintained by the macro pilcoRecord
 
# gPlicoRecord is maintained by the macro pilcoRecord
function translateSelectedRecord(pt) {
+
function translate_selected_record(pt) {
 
     if (gPlicoRecord != "") {
 
     if (gPlicoRecord != "") {
         plicoRecord(format("select %s;translateSelected %s;", {selected}, pt))
+
         plico_record(format("select %s;translateSelected %s;", {selected}, pt))
 
     }
 
     }
 
     translateSelected @pt
 
     translateSelected @pt
Line 982: Line 976:
  
 
# gPlicoRecord is maintained by the macro pilcoRecord
 
# gPlicoRecord is maintained by the macro pilcoRecord
function rotateSelectedRecord(pivotIdx, axis, a) {
+
function rotate_selected_record(pivotIdx, axis, a) {
 
     if (gPlicoRecord != "") {
 
     if (gPlicoRecord != "") {
         plicoRecord(format("select %s;", {selected}))
+
         plico_record(format("select %s;", {selected}))
         plicoRecord(format("rotateSelected {atomIndex=%d} @%s @%s;",
+
         plico_record(format("rotateSelected {atomIndex=%d} @%s @%s;",
 
             pivotIdx, axis, a))
 
             pivotIdx, axis, a))
 
     }
 
     }
Line 991: Line 985:
 
}
 
}
  
function collectSCrotors(no, iChain) {
+
function collect_sc_rotors(no, iChain) {
 
     var scBondIdxs = array()
 
     var scBondIdxs = array()
 
     for (var iNo = no; iNo >= 0; iNo--) {
 
     for (var iNo = no; iNo >= 0; iNo--) {
Line 1,041: Line 1,035:
  
 
# Drag Side Chain
 
# Drag Side Chain
function dragSC() {
+
function drag_sc() {
  
 
     var iNo = {atomIndex=gSCidx}.atomno
 
     var iNo = {atomIndex=gSCidx}.atomno
Line 1,048: Line 1,042:
 
     if ({atomIndex=gSCidx}.group != "PRO") {
 
     if ({atomIndex=gSCidx}.group != "PRO") {
  
         var scBondIdxs = collectSCrotors( iNo, iChain)
+
         var scBondIdxs = collect_sc_rotors( iNo, iChain)
 
         var numChi = scBondIdxs.size / 4
 
         var numChi = scBondIdxs.size / 4
 
         var dist = distance({atomIndex=gSCidx}.xyz, gSCpt)
 
         var dist = distance({atomIndex=gSCidx}.xyz, gSCpt)
Line 1,054: Line 1,048:
 
         var scSet = ({})
 
         var scSet = ({})
 
         if (gSCcheck) {
 
         if (gSCcheck) {
             scSet = getScSet(gSCidx, iChain)
+
             scSet = get_sc_set(gSCidx, iChain)
 
         }
 
         }
 
          
 
          
Line 1,069: Line 1,063:
 
             for (var j = 0; j < 6; j++) {
 
             for (var j = 0; j < 6; j++) {
 
                 rot += 60*j
 
                 rot += 60*j
                 selectAddSideChain(scBondIdxs[1+(4*i)])
+
                 select_add_sc(scBondIdxs[1+(4*i)])
                 setDihedralIdx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)],
+
                 set_dihedral_idx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)],
 
                     scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], rot)
 
                     scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], rot)
 
                 var newDist = distance({atomIndex=gSCidx}.xyz, gSCpt)
 
                 var newDist = distance({atomIndex=gSCidx}.xyz, gSCpt)
Line 1,096: Line 1,090:
 
         # Now set the best
 
         # Now set the best
 
         for (var i = 0; i < numChi; i++) {
 
         for (var i = 0; i < numChi; i++) {
             selectAddSideChain(scBondIdxs[1+(4*i)])
+
             select_add_sc(scBondIdxs[1+(4*i)])
             setDihedralIdx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)],
+
             set_dihedral_idx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)],
 
                 scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], dh[i+1])
 
                 scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], dh[i+1])
 
         }
 
         }
Line 1,110: Line 1,104:
 
         if (angle({atomIndex=ica}, {atomIndex=in},
 
         if (angle({atomIndex=ica}, {atomIndex=in},
 
             {atomIndex=icd}, {atomIndex=gSCidx}) < -10.0) {
 
             {atomIndex=icd}, {atomIndex=gSCidx}) < -10.0) {
             setDihedralIdx(ica, in, icd, gSCidx, 8.7)
+
             set_dihedral_idx(ica, in, icd, gSCidx, 8.7)
             setAngleIdx(in, icd, gSCidx, 110.0)
+
             set_angle_idx(in, icd, gSCidx, 110.0)
             setDistanceIdx(icd, gSCidx, 1.5)
+
             set_distance_idx(icd, gSCidx, 1.5)
 
         }
 
         }
 
         else {
 
         else {
             setDihedralIdx(ica, in, icd, gSCidx, -29.5)
+
             set_dihedral_idx(ica, in, icd, gSCidx, -29.5)
             setAngleIdx(in, icd, gSCidx, 108.8)
+
             set_angle_idx(in, icd, gSCidx, 108.8)
             setDistanceIdx(icd, gSCidx, 1.5)
+
             set_distance_idx(icd, gSCidx, 1.5)
 
         }
 
         }
 
     }
 
     }
Line 1,126: Line 1,120:
  
 
# Fix side chain collisions
 
# Fix side chain collisions
function fixSCcollision2(idx) {
+
function fix_sc_collision_2(idx) {
 
     gOk2 = FALSE
 
     gOk2 = FALSE
 
     var iNo = {atomIndex=idx}.atomno
 
     var iNo = {atomIndex=idx}.atomno
Line 1,146: Line 1,140:
 
     var cbidx = {(atomno=iBno) and (chain=iChain)}.atomIndex
 
     var cbidx = {(atomno=iBno) and (chain=iChain)}.atomIndex
  
     var scBondIdxs = collectSCrotors( iNo, iChain)
+
     var scBondIdxs = collect_sc_rotors( iNo, iChain)
 
     var numChi = scBondIdxs.size / 4
 
     var numChi = scBondIdxs.size / 4
  
Line 1,154: Line 1,148:
 
         for (var j = 0; j < 6; j++) {
 
         for (var j = 0; j < 6; j++) {
 
             rot += 60
 
             rot += 60
             selectAddSideChain(scBondIdxs[1+(4*i)])
+
             select_add_sc(scBondIdxs[1+(4*i)])
             setDihedralIdx(scBondIdxs[1+(4*i)], scBondIdxs[2+(4*i)],
+
             set_dihedral_idx(scBondIdxs[1+(4*i)], scBondIdxs[2+(4*i)],
 
                 scBondIdxs[3+(4*i)], scBondIdxs[4+(4*i)], rot)
 
                 scBondIdxs[3+(4*i)], scBondIdxs[4+(4*i)], rot)
 
                  
 
                  
Line 1,179: Line 1,173:
 
}
 
}
  
function isMovableSideChain(aIdx) {
+
function is_moveable_sc(aIdx) {
  
 
     var ret = (({atomIndex=aIdx}.group != "PRO")
 
     var ret = (({atomIndex=aIdx}.group != "PRO")
Line 1,196: Line 1,190:
 
}
 
}
  
function isRotorAvailable(i1idx, i2idx) {
+
function is_rotor_avail(i1idx, i2idx) {
 
     var ret = TRUE
 
     var ret = TRUE
 
     if (i1idx > i2idx) {
 
     if (i1idx > i2idx) {
Line 1,214: Line 1,208:
 
}
 
}
  
function collectBBrotors(nWard) {
+
function collect_bb_rotors(nWard) {
 
     var anchorNo = (nWard
 
     var anchorNo = (nWard
 
         ? ((gNanchorIdx >= 0) ? {atomIndex=gNanchorIdx}.atomno : gMinNo)
 
         ? ((gNanchorIdx >= 0) ? {atomIndex=gNanchorIdx}.atomno : gMinNo)
Line 1,227: Line 1,221:
 
         for (var iNo = cargoNo; iNo <= anchorNo; iNo++) {
 
         for (var iNo = cargoNo; iNo <= anchorNo; iNo++) {
 
             if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") {
 
             if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") {
                 if (isRotorAvailable(iNo)) {
+
                 if (is_rotor_avail(iNo)) {
 
                     if (({(atomno=iNo) and (chain=gChain)}.group != "PRO") and (iNo > cargoNo)) { # phi
 
                     if (({(atomno=iNo) and (chain=gChain)}.group != "PRO") and (iNo > cargoNo)) { # phi
                         rotors += [{(atomno=@{getCmNo(iNo-1)}) and (chain=gChain)}.atomIndex,
+
                         rotors += [{(atomno=@{get_cm_no(iNo-1)}) and (chain=gChain)}.atomIndex,
 
                             {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex]
 
                             {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex]
 
                         rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex,
 
                         rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex,
Line 1,238: Line 1,232:
 
                             {(atomno=@{iNo}) and (chain=gChain)}.atomIndex]
 
                             {(atomno=@{iNo}) and (chain=gChain)}.atomIndex]
 
                         rotors += [{(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex,
 
                         rotors += [{(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex,
                             {(atomno=@{getNpNo(iNo+2)}) and (chain=gChain)}.atomIndex]
+
                             {(atomno=@{get_np_no(iNo+2)}) and (chain=gChain)}.atomIndex]
 
                     }
 
                     }
 
                 }
 
                 }
Line 1,248: Line 1,242:
 
         for (var iNo = cargoNo; iNo >= anchorNo; iNo--) {
 
         for (var iNo = cargoNo; iNo >= anchorNo; iNo--) {
 
             if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") {
 
             if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") {
                 if (isRotorAvailable(iNo)) {
+
                 if (is_rotor_avail(iNo)) {
 
                     if ((iNo != (anchorNo-1)) and (iNo < cargoNo)) { # psi
 
                     if ((iNo != (anchorNo-1)) and (iNo < cargoNo)) { # psi
                         rotors += [{(atomno=@{getNpNo(iNo+2)}) and (chain=gChain)}.atomIndex,
+
                         rotors += [{(atomno=@{get_np_no(iNo+2)}) and (chain=gChain)}.atomIndex,
 
                             {(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex]
 
                             {(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex]
 
                         rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex,
 
                         rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex,
Line 1,259: Line 1,253:
 
                             {(atomno=@{iNo}) and (chain=gChain)}.atomIndex]
 
                             {(atomno=@{iNo}) and (chain=gChain)}.atomIndex]
 
                         rotors += [{(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex,
 
                         rotors += [{(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex,
                             {(atomno=@{getCmNo(iNo-1)}) and (chain=gChain)}.atomIndex]
+
                             {(atomno=@{get_cm_no(iNo-1)}) and (chain=gChain)}.atomIndex]
 
                     }
 
                     }
 
                 }
 
                 }
Line 1,274: Line 1,268:
 
}
 
}
  
function collectRotors() {
+
function collect_rotors() {
     collectBBrotors(FALSE)
+
     collect_bb_rotors(FALSE)
     collectBBrotors(TRUE)
+
     collect_bb_rotors(TRUE)
 
}
 
}
  
function tugSideChain(pt) {
+
function tug_sc(pt) {
  
 
     # If destination atom defined
 
     # If destination atom defined
Line 1,295: Line 1,289:
 
}
 
}
  
function setColors() {
+
function set_colors() {
 
     select all
 
     select all
 
     color {selected} @gScheme
 
     color {selected} @gScheme
Line 1,309: Line 1,303:
 
}
 
}
  
function clearAtomIdxs() {
+
function clear_atom_idxs() {
 
     gCcargoIdx = -1
 
     gCcargoIdx = -1
 
     gNcargoIdx = -1
 
     gNcargoIdx = -1
Line 1,322: Line 1,316:
 
}
 
}
  
function timedOut (s) {
+
function timed_out (s) {
 
     timeout ID"tug" OFF
 
     timeout ID"tug" OFF
 
     p = prompt(format("%s - Undo?", s), "Yes|No", TRUE)
 
     p = prompt(format("%s - Undo?", s), "Yes|No", TRUE)
Line 1,336: Line 1,330:
 
}
 
}
  
function recordDrag() {
+
function record_drag() {
 
     var ls = format("select %s;", {selected})
 
     var ls = format("select %s;", {selected})
 
     ls += format("gCanchorIdx = %d;", gCanchorIdx)
 
     ls += format("gCanchorIdx = %d;", gCanchorIdx)
Line 1,357: Line 1,351:
 
     ls += format("gSCcircle = %d;", gSCcircle)
 
     ls += format("gSCcircle = %d;", gSCcircle)
 
     ls += format("gSCpt = %s;", gSCpt)
 
     ls += format("gSCpt = %s;", gSCpt)
     ls += "collectRotors();"
+
     ls += "collect_rotors();"
     ls += "tugDragDoneMB();"
+
     ls += "tug_drag_done_mb();"
     plicoRecord(ls)
+
     plico_record(ls)
 
}
 
}
  
 
# Pick call-back for freeze
 
# Pick call-back for freeze
function tugPickCB() {
+
function tug_pick_cb() {
  
 
     if (_pickInfo[3][6] == "bond") {
 
     if (_pickInfo[3][6] == "bond") {
Line 1,405: Line 1,399:
 
}
 
}
  
# Bound to LEFT-UP by tugEnableDrag
+
# Bound to LEFT-UP by tug_enable_drag
function tugDragDoneMB() {
+
function tug_drag_done_mb() {
 
     if (not gBusy) {
 
     if (not gBusy) {
 
         if (gPlicoRecord != "") {
 
         if (gPlicoRecord != "") {
             recordDrag()
+
             record_drag()
 
         }
 
         }
  
Line 1,419: Line 1,413:
 
         # If side chain mode
 
         # If side chain mode
 
         if (gSCidx >= 0) {
 
         if (gSCidx >= 0) {
             dragSC()
+
             drag_sc()
 
         }
 
         }
  
Line 1,425: Line 1,419:
 
         else if (not gTow) {
 
         else if (not gTow) {
 
             gOK = TRUE
 
             gOK = TRUE
             timeout ID"tug" 20.0 "timedOut(\"Tug timed out\")"
+
             timeout ID"tug" 20.0 "timed_out(\"Tug timed out\")"
 
             if ((gCrotors.size < gNrotors.size) or (gNanchorIdx < 0)) {
 
             if ((gCrotors.size < gNrotors.size) or (gNanchorIdx < 0)) {
 
                 if (gCrotors.size > 4) {
 
                 if (gCrotors.size > 4) {
                     tugTrackC()
+
                     tug_track_c()
 
                 }
 
                 }
 
                 if (gOK and (gNrotors.size > 4)) {
 
                 if (gOK and (gNrotors.size > 4)) {
                     tugTrackN()
+
                     tug_track_n()
 
                 }
 
                 }
 
             }
 
             }
 
             else {
 
             else {
 
                 if (gNrotors.size > 4) {
 
                 if (gNrotors.size > 4) {
                     tugTrackN()
+
                     tug_track_n()
 
                 }
 
                 }
 
                 if (gOK and (gCrotors.size > 4)) {
 
                 if (gOK and (gCrotors.size > 4)) {
                     tugTrackC()
+
                     tug_track_c()
 
                 }
 
                 }
 
             }
 
             }
Line 1,447: Line 1,441:
 
             if (gOK == TRUE) {
 
             if (gOK == TRUE) {
 
                 if (gCanchorIdx >= 0) {
 
                 if (gCanchorIdx >= 0) {
                     var ic = getCwardBBidx(gCanchorIdx, gChain)
+
                     var ic = get_cward_bb_idx(gCanchorIdx, gChain)
                     var in = getNwardBBidx(gCanchorIdx, gChain)
+
                     var in = get_nward_bb_idx(gCanchorIdx, gChain)
 
                     if ((ic >= 0) and
 
                     if ((ic >= 0) and
 
                         angle({atomIndex=ic}, {atomIndex=gCanchorIdx}, {atomIndex=in})
 
                         angle({atomIndex=ic}, {atomIndex=gCanchorIdx}, {atomIndex=in})
Line 1,456: Line 1,450:
 
                 }
 
                 }
 
                 if (gNanchorIdx >= 0) {
 
                 if (gNanchorIdx >= 0) {
                     var ic = getCwardBBidx(gNanchorIdx, gChain)
+
                     var ic = get_cward_bb_idx(gNanchorIdx, gChain)
                     var in = getNwardBBidx(gNanchorIdx, gChain)
+
                     var in = get_nward_bb_idx(gNanchorIdx, gChain)
 
                     if ((in >= 0) and
 
                     if ((in >= 0) and
 
                         angle({atomIndex=ic}, {atomIndex=gNanchorIdx}, {atomIndex=in})
 
                         angle({atomIndex=ic}, {atomIndex=gNanchorIdx}, {atomIndex=in})
Line 1,468: Line 1,462:
 
             # If too far
 
             # If too far
 
             if (not gOK) {
 
             if (not gOK) {
                 timedOut("TUG TOO FAR!")
+
                 timed_out("TUG TOO FAR!")
 
             }
 
             }
  
Line 1,482: Line 1,476:
 
                 var ihc = 0
 
                 var ihc = 0
 
                 for (ihc = 0; ihc < 10; ihc++) {
 
                 for (ihc = 0; ihc < 10; ihc++) {
                     handleCollisions2( idx)
+
                     handle_collisions_2( idx)
                     if (countCollisions(({})) == 0) {
+
                     if (count_collisions(({})).size == 0) {
 
                         break
 
                         break
 
                     }
 
                     }
 
                 }
 
                 }
 
                 if (ihc == 10) {
 
                 if (ihc == 10) {
                     timedOut("Unable to handle all collisions!")
+
                     timed_out("Unable to handle all collisions!")
 
                 }
 
                 }
 
             }
 
             }
Line 1,499: Line 1,493:
 
}
 
}
  
# Bound to ALT-SHIFT-LEFT-DRAG by tugEnableDrag
+
# Bound to ALT-SHIFT-LEFT-DRAG by tug_enable_drag
function tugDrag2MB() {
+
function tug_drag_2_mb() {
     tugDragMB(TRUE)
+
     tug_drag_mb(TRUE)
 
}
 
}
  
# Bound to ALT-LEFT-DRAG by tugEnableDrag
+
# Bound to ALT-LEFT-DRAG by tug_enable_drag
function tugDragMB(alt) {
+
function tug_drag_mb(alt) {
 
     if (not gBusy) {
 
     if (not gBusy) {
 
         gBusy = TRUE
 
         gBusy = TRUE
Line 1,521: Line 1,515:
 
                         ? ((dx < 0) ? 10 : -10)
 
                         ? ((dx < 0) ? 10 : -10)
 
                         : ((dy < 0) ? 1 : -1))
 
                         : ((dy < 0) ? 1 : -1))
                     counterRotate(gSCidx, dir, not alt)
+
                     counter_rotate(gSCidx, dir, not alt)
 
                 }
 
                 }
 
                 else {
 
                 else {
 
                     gSCcheck = not alt
 
                     gSCcheck = not alt
                     tugSideChain(pt)
+
                     tug_sc(pt)
 
                 }
 
                 }
 
             }
 
             }
Line 1,568: Line 1,562:
 
                         ? ((dx < 0) ? 2 : -2)
 
                         ? ((dx < 0) ? 2 : -2)
 
                         : ((dy < 0) ? 2 : -2))
 
                         : ((dy < 0) ? 2 : -2))
                     rotateSelectedRecord(g1pivotIdx, axis, dir)
+
                     rotate_selected_record(g1pivotIdx, axis, dir)
  
 
                 }
 
                 }
Line 1,574: Line 1,568:
 
                 # Else translate it
 
                 # Else translate it
 
                 else {
 
                 else {
                     translateSelectedRecord(pt)
+
                     translate_selected_record(pt)
 
                 }
 
                 }
  
Line 1,598: Line 1,592:
 
                                         g1dynamicIdx = cNotSels[i].atomIndex
 
                                         g1dynamicIdx = cNotSels[i].atomIndex
 
                                         color {atomIndex=g1pivotIdx} lightgreen
 
                                         color {atomIndex=g1pivotIdx} lightgreen
                                         setDistanceIdx(cNotSels[i].atomIndex,
+
                                         set_distance_idx(cNotSels[i].atomIndex,
 
                                             cSels[j].atomIndex,
 
                                             cSels[j].atomIndex,
 
                                             kCtolerance + kDtolerance)
 
                                             kCtolerance + kDtolerance)
Line 1,606: Line 1,600:
 
                                         g2dynamicIdx = cNotSels[i].atomIndex
 
                                         g2dynamicIdx = cNotSels[i].atomIndex
 
                                         color {atomIndex=g2pivotIdx} lightgreen
 
                                         color {atomIndex=g2pivotIdx} lightgreen
                                         setDistanceIdx(cNotSels[i].atomIndex,
+
                                         set_distance_idx(cNotSels[i].atomIndex,
 
                                             cSels[j].atomIndex,
 
                                             cSels[j].atomIndex,
 
                                             kCtolerance + kDtolerance)
 
                                             kCtolerance + kDtolerance)
Line 1,620: Line 1,614:
 
                                     var idx = {(atomno=@{{chain=gChain}.atomno.min})
 
                                     var idx = {(atomno=@{{chain=gChain}.atomno.min})
 
                                         and (chain=gChain)}.atomIndex
 
                                         and (chain=gChain)}.atomIndex
                                     handleCollisions2( idx)
+
                                     handle_collisions_2( idx)
 
                                 }
 
                                 }
 
                             }
 
                             }
Line 1,636: Line 1,630:
 
                         delay 1
 
                         delay 1
 
                         if (g1pivotIdx >= 0) {
 
                         if (g1pivotIdx >= 0) {
                             rotateSelectedRecord(g1pivotIdx, axis, -a)
+
                             rotate_selected_record(g1pivotIdx, axis, -a)
 
                         }
 
                         }
 
                         else {
 
                         else {
                             translateSelectedRecord(-pt)
+
                             translate_selected_record(-pt)
 
                         }
 
                         }
 
                         background ECHO yellow
 
                         background ECHO yellow
Line 1,673: Line 1,667:
 
}
 
}
  
# Bound to ALT-LEFT-DOWN by tugEnableDrag
+
# Bound to ALT-LEFT-DOWN by tug_enable_drag
function tugMarkMB() {
+
function tug_mark_mb() {
 
     gMouseX = _mouseX
 
     gMouseX = _mouseX
 
     gMouseY = _mouseY
 
     gMouseY = _mouseY
Line 1,680: Line 1,674:
 
}
 
}
  
# Called by tugCargoMB
+
# Called by tug_cargo_mb
function tugEnableDrag() {
+
function tug_enable_drag() {
 
     gEcho = "__________TUG__________|ALT-CLICK=mark block|SHIFT-CLICK=anchors" +
 
     gEcho = "__________TUG__________|ALT-CLICK=mark block|SHIFT-CLICK=anchors" +
 
         "|ALT-CTRL-CLICK=pivots|ALT-SHIFT-CLICK=dest atom|ALT-DRAG=move" +
 
         "|ALT-CTRL-CLICK=pivots|ALT-SHIFT-CLICK=dest atom|ALT-DRAG=move" +
Line 1,688: Line 1,682:
  
 
     # Allow atoms to be dragged
 
     # Allow atoms to be dragged
     bind "ALT-LEFT-DOWN" "tugMarkMB";
+
     bind "ALT-LEFT-DOWN" "tug_mark_mb";
     bind "ALT-LEFT-UP" "tugDragDoneMB";
+
     bind "ALT-LEFT-UP" "tug_drag_done_mb";
     bind "ALT-SHIFT-LEFT-DOWN" "tugMarkMB";
+
     bind "ALT-SHIFT-LEFT-DOWN" "tug_mark_mb";
     bind "ALT-SHIFT-LEFT-UP" "tugDragDoneMB";
+
     bind "ALT-SHIFT-LEFT-UP" "tug_drag_done_mb";
     bind "ALT-LEFT-DRAG" "tugDragMB";
+
     bind "ALT-LEFT-DRAG" "tug_drag_mb";
     bind "ALT-SHIFT-LEFT-DRAG" "tugDrag2MB";
+
     bind "ALT-SHIFT-LEFT-DRAG" "tug_drag_2_mb";
  
 
     unbind "SHIFT-LEFT-CLICK"
 
     unbind "SHIFT-LEFT-CLICK"
 
     bind "SHIFT-LEFT-CLICK" "_pickAtom";
 
     bind "SHIFT-LEFT-CLICK" "_pickAtom";
     bind "SHIFT-LEFT-CLICK" "+:tugAnchorMB";
+
     bind "SHIFT-LEFT-CLICK" "+:tug_anchor_mb";
  
 
     bind "ALT-CTRL-LEFT-CLICK" "_pickAtom";
 
     bind "ALT-CTRL-LEFT-CLICK" "_pickAtom";
     bind "ALT-CTRL-LEFT-CLICK" "+:tugPivotMB";
+
     bind "ALT-CTRL-LEFT-CLICK" "+:tug_pivot_mb";
  
 
     bind "ALT-SHIFT-LEFT-CLICK" "_pickAtom";
 
     bind "ALT-SHIFT-LEFT-CLICK" "_pickAtom";
     bind "ALT-SHIFT-LEFT-CLICK" "+:tugDestAtomMB";
+
     bind "ALT-SHIFT-LEFT-CLICK" "+:tug_dest_atom_mb";
 
}
 
}
  
# Bound to SHIFT-LEFT-CLICK by tugCargoMB
+
# Bound to SHIFT-LEFT-CLICK by tug_cargo_mb
function tugAnchorMB() {
+
function tug_anchor_mb() {
 
     if ({atomIndex=_atomPicked}.chain == gChain) {
 
     if ({atomIndex=_atomPicked}.chain == gChain) {
         var aPidx = getScBBidx( _atomPicked, gChain)
+
         var aPidx = get_sc_bb_idx( _atomPicked, gChain)
  
 
         var pno = {atomIndex=aPidx}.atomno
 
         var pno = {atomIndex=aPidx}.atomno
Line 1,725: Line 1,719:
 
                 halo on
 
                 halo on
 
             }
 
             }
             collectBBrotors(FALSE)
+
             collect_bb_rotors(FALSE)
 
         }
 
         }
 
         else if (pno < {atomIndex=gNcargoIdx}.atomno) {
 
         else if (pno < {atomIndex=gNcargoIdx}.atomno) {
Line 1,740: Line 1,734:
 
                 halo on
 
                 halo on
 
             }
 
             }
             collectBBrotors(TRUE)
+
             collect_bb_rotors(TRUE)
 
         }
 
         }
 
         else {
 
         else {
             towCargoMB()
+
             tow_cargo_mb()
 
         }
 
         }
  
Line 1,753: Line 1,747:
 
}
 
}
  
# Bound to ALT-SHIFT-LEFT-CLICK by tugCargoMB
+
# Bound to ALT-SHIFT-LEFT-CLICK by tug_cargo_mb
function tugDestAtomMB() {
+
function tug_dest_atom_mb() {
 
     var aOk = TRUE
 
     var aOk = TRUE
 
     if ({atomIndex=_atomPicked}.chain == gChain) {
 
     if ({atomIndex=_atomPicked}.chain == gChain) {
Line 1,778: Line 1,772:
 
}
 
}
  
# Bound to CTRL-LEFT-CLICK by tugCargoMB
+
# Bound to CTRL-LEFT-CLICK by tug_cargo_mb
function tugPivotMB() {
+
function tug_pivot_mb() {
 
     if (g1pivotIdx == _atomPicked) {
 
     if (g1pivotIdx == _atomPicked) {
 
         color {atomIndex=g1pivotIdx} @gScheme
 
         color {atomIndex=g1pivotIdx} @gScheme
Line 1,814: Line 1,808:
 
}
 
}
  
# Bound to SHIFT-LEFT-CLICK by plicoTug
+
# Bound to SHIFT-LEFT-CLICK by plico_tug
function towCargoMB() {
+
function tow_cargo_mb() {
 
     gTow = TRUE
 
     gTow = TRUE
 
     gChain = {atomIndex=_atomPicked}.chain
 
     gChain = {atomIndex=_atomPicked}.chain
Line 1,831: Line 1,825:
 
     gCargoSet = {selected}
 
     gCargoSet = {selected}
 
     gMovingSet = {selected}
 
     gMovingSet = {selected}
     setColors()
+
     set_colors()
  
 
     # Enable dragging
 
     # Enable dragging
     tugEnableDrag()
+
     tug_enable_drag()
 
     select {gCargoSet}
 
     select {gCargoSet}
 
     halo off
 
     halo off
Line 1,841: Line 1,835:
 
     unbind "SHIFT-LEFT-CLICK"
 
     unbind "SHIFT-LEFT-CLICK"
 
     bind "SHIFT-LEFT-CLICK" "_pickAtom";
 
     bind "SHIFT-LEFT-CLICK" "_pickAtom";
     bind "SHIFT-LEFT-CLICK" "+:towCargoMB";
+
     bind "SHIFT-LEFT-CLICK" "+:tow_cargo_mb";
 
}
 
}
  
# Bound to ALT-LEFT-CLICK by plicoTug or called by plicotoab.toabCargoMB
+
# Bound to ALT-LEFT-CLICK by plico_tug or called by plicotoab.toabCargoMB
function tugCargoMB() {
+
function tug_cargo_mb() {
  
 
     # If O or movable side chain atom picked
 
     # If O or movable side chain atom picked
 
     if (({atomIndex=_atomPicked}.atomName = "O")
 
     if (({atomIndex=_atomPicked}.atomName = "O")
         or (isMovableSideChain( _atomPicked))) {
+
         or (is_moveable_sc( _atomPicked))) {
 
         if (gSCidx >= 0) {
 
         if (gSCidx >= 0) {
 
             draw gSCcircle DELETE
 
             draw gSCcircle DELETE
Line 1,886: Line 1,880:
 
             gCanchorNo = gMaxNo + 1
 
             gCanchorNo = gMaxNo + 1
 
         }
 
         }
         var aPidx = getScBBidx( _atomPicked, gChain)
+
         var aPidx = get_sc_bb_idx( _atomPicked, gChain)
  
 
         gSCidx = -1
 
         gSCidx = -1
Line 1,900: Line 1,894:
 
             # If nWard cargo exists, mark it as the cWard cargo
 
             # If nWard cargo exists, mark it as the cWard cargo
 
             if (gNcargoIdx != gCcargoIdx) {
 
             if (gNcargoIdx != gCcargoIdx) {
                 gCcargoIdx = getCpIdx(gNcargoIdx)
+
                 gCcargoIdx = get_cp_idx(gNcargoIdx)
 
                 gCcargoNo = {atomIndex=gCcargoIdx}.atomno
 
                 gCcargoNo = {atomIndex=gCcargoIdx}.atomno
 
             }
 
             }
Line 1,911: Line 1,905:
 
             select {atomIndex=gNcargoIdx}
 
             select {atomIndex=gNcargoIdx}
 
             halo off
 
             halo off
             gNcargoIdx = getNmIdx(gCcargoIdx)
+
             gNcargoIdx = get_nm_idx(gCcargoIdx)
 
             gNcargoNo = {atomIndex=gNcargoIdx}.atomno
 
             gNcargoNo = {atomIndex=gNcargoIdx}.atomno
 
         }
 
         }
Line 1,928: Line 1,922:
  
 
                 # Set new nWard cargo and highlight it
 
                 # Set new nWard cargo and highlight it
                 gNcargoIdx = getNmIdx(aPidx)
+
                 gNcargoIdx = get_nm_idx(aPidx)
 
                 gNcargoNo = {atomIndex=gNcargoIdx}.atomno
 
                 gNcargoNo = {atomIndex=gNcargoIdx}.atomno
 
             }
 
             }
Line 1,942: Line 1,936:
  
 
                 # Set new cWard cargo and highlight
 
                 # Set new cWard cargo and highlight
                 gCcargoIdx = getCpIdx(aPidx)
+
                 gCcargoIdx = get_cp_idx(aPidx)
 
                 gCcargoNo = {atomIndex=gCcargoIdx}.atomno
 
                 gCcargoNo = {atomIndex=gCcargoIdx}.atomno
 
             }
 
             }
Line 1,951: Line 1,945:
  
 
             # Set new cWard cargo and highlight
 
             # Set new cWard cargo and highlight
             gCcargoIdx = getCpIdx(aPidx)
+
             gCcargoIdx = get_cp_idx(aPidx)
 
             gCcargoNo = {atomIndex=gCcargoIdx}.atomno
 
             gCcargoNo = {atomIndex=gCcargoIdx}.atomno
             gNcargoIdx = getNmIdx(gCcargoIdx)
+
             gNcargoIdx = get_nm_idx(gCcargoIdx)
 
             gNcargoNo = {atomIndex=gNcargoIdx}.atomno
 
             gNcargoNo = {atomIndex=gNcargoIdx}.atomno
  
Line 1,978: Line 1,972:
  
 
         # Highlight cargo cluster
 
         # Highlight cargo cluster
         selectNwardIdx(gCcargoIdx, gNcargoIdx)
+
         select_nward_idx(gCcargoIdx, gNcargoIdx)
 
         gCargoSet = {selected}
 
         gCargoSet = {selected}
         setColors()
+
         set_colors()
  
 
         # Collect the rotor sets
 
         # Collect the rotor sets
         collectRotors()
+
         collect_rotors()
  
 
         # Get moving atoms set
 
         # Get moving atoms set
Line 1,995: Line 1,989:
 
     }
 
     }
 
     else {
 
     else {
         tugEnableDrag()
+
         tug_enable_drag()
 
     }
 
     }
 
      
 
      
Line 2,002: Line 1,996:
  
 
# Top level of Tug
 
# Top level of Tug
function plicoTug() {
+
function plico_tug() {
  
 
     # Load common functions if not already
 
     # Load common functions if not already
     if (kCommon < 1) {
+
     if (kCommon < 2) {
 
         script $SCRIPT_PATH$plicoCommon.spt
 
         script $SCRIPT_PATH$plicoCommon.spt
         if (kCommon < 1) {
+
         if (kCommon < 2) {
 
             prompt ("A newer version of plicoCommon.SPT is required")
 
             prompt ("A newer version of plicoCommon.SPT is required")
 
             quit
 
             quit
Line 2,014: Line 2,008:
 
      
 
      
 
     gPlico = "TUG"
 
     gPlico = "TUG"
     plicoPrelim()
+
     plico_prelim()
 
     gBondPicking = bondPicking
 
     gBondPicking = bondPicking
 
     set bondPicking TRUE
 
     set bondPicking TRUE
     set PickCallback "jmolscript:tugPickCB"
+
     set PickCallback "jmolscript:tug_pick_cb"
 
              
 
              
 
     gEcho = ("_________TUG_________|ALT-CLICK=mark block|SHIFT-CLICK=mark chain" +
 
     gEcho = ("_________TUG_________|ALT-CLICK=mark block|SHIFT-CLICK=mark chain" +
Line 2,024: Line 2,018:
 
     gCrotors = array()
 
     gCrotors = array()
 
     gNrotors = array()
 
     gNrotors = array()
     clearAtomIdxs()
+
     clear_atom_idxs()
  
 
     bind "ALT-LEFT-CLICK" "_pickAtom";
 
     bind "ALT-LEFT-CLICK" "_pickAtom";
     bind "ALT-LEFT-CLICK" "+:tugCargoMB";
+
     bind "ALT-LEFT-CLICK" "+:tug_cargo_mb";
 
     bind "SHIFT-LEFT-CLICK" "_pickAtom";
 
     bind "SHIFT-LEFT-CLICK" "_pickAtom";
     bind "SHIFT-LEFT-CLICK" "+:towCargoMB";
+
     bind "SHIFT-LEFT-CLICK" "+:tow_cargo_mb";
     bind "DOUBLE" "tugExit";
+
     bind "DOUBLE" "tug_exit";
 
}
 
}
  
# Bound to DOUBLE by plicoTug
+
# Bound to DOUBLE by plico_tug
function tugExit() {
+
function tug_exit() {
 
     set bondPicking gBondPicking
 
     set bondPicking gBondPicking
 
     set PickCallback NONE
 
     set PickCallback NONE
     plicoExit()
+
     plico_exit()
 
}
 
}
  
 
# End of TUG.SPT</pre>
 
# End of TUG.SPT</pre>

Revision as of 15:07, 16 May 2014

Tug allows the user to pull or push by mouse actions to move or rotate one part of a polypeptide against the rest by rotation on its psi and phi bonds with collision detection and restriction. It also allows the user to move an entire chain to nest against another chain.

Tug is a member of the Plico suite of protein folding tools described in User:Remig/plico . It may be installed and accessed as a macro with the file:

Title=PLICO Tug
Script=script <path to your scripts folder>/tug.spt;plicotug

saved as plicotug.macro in your .jmol/macros directory as described in Macro.

Copy and paste the following into a text editor and save in your scripts folder as tug.spt.

#   tug - Jmol script by Ron Mignery
#   v1.11 beta    5/16/2014 -lc all functions
#
#   Translate or rotate a stretch of a polypeptide against itself
#    or against other chains by mouse actions
#
kTug = 3
gCanchorIdx = -1
gCanchorNo = -1
gPlico = "TUG"
gNanchorIdx = -1
gNanchorNo = -1
gCcargoIdx = -1
gNcargoIdx = -1
gCcargoNo = -1
gNcargoNo = -1
gDestAtomIdx = -1
g1pivotIdx = -1
g2pivotIdx = -1
gSelSaves = ({})
gCrotors = array()
gNrotors = array()
gOkCollide = ({})
gChain = ""
gMinNo = 1
gMaxNo = 9999
gCargoSet = ({})
gMovingSet = ({})
gBusy = FALSE
gSCidx = -1
gSCcircle = -1
gSCpt = {0 0 0}
gTargetPt = {0 0 0}
gNewDrag = FALSE
gEcho = ""
gZoom = ""
gRotate = ""
gTow = FALSE
g1dynamicIdx = -1
g2dynamicIdx = -1
gSCcheck = TRUE
gBondPicking = FALSE


function get_cam_no (iNo) {
    while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) {
        iNo--
    }
    return iNo
}

function get_cam_idx (idx) {
    var no = {atomIndex=idx and (chain=gChain)}.atomno
    no = get_cam_no( no)
    return ({(atomno=no) and (chain=gChain)}.atomIndex)
}

function get_cap_no (iNo) {
    while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) {
        iNo++
    }
    return iNo
}

function getCApIdx (idx) {
    var no = {atomIndex=idx and (chain=gChain)}.atomno
    no = get_cap_no( no)
    return ({(atomno=no) and (chain=gChain)}.atomIndex)
}

function get_cp_no (iNo) {
    while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) {
        iNo++
    }
    return iNo
}

function get_cp_idx (idx) {
    var no = {atomIndex=idx and (chain=gChain)}.atomno
    no = get_cp_no( no)
    return ({(atomno=no) and (chain=gChain)}.atomIndex)
}

function get_cm_no (iNo) {
    while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) {
        iNo--
    }
    return iNo
}

function get_cm_idx (idx) {
    var no = {atomIndex=idx and (chain=gChain)}.atomno
    no = get_cm_no( no)
    return ({(atomno=no) and (chain=gChain)}.atomIndex)
}

function get_nm_no (iNo) {
    while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) {
        iNo--
    }
    return iNo
}

function get_nm_idx (idx) {
    var no = {atomIndex=idx and (chain=gChain)}.atomno
    no = get_nm_no( no)
    return ({(atomno=no) and (chain=gChain)}.atomIndex)
}

function get_np_no (iNo) {
    while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) {
        iNo++
    }
    return iNo
}

function get_np_idx (idx) {
    var no = {atomIndex=idx}.atomno
    no = get_np_no( no)
    return ({(atomno=no) and (chain=gChain)}.atomIndex)
}

function get_cb_idx (BBidx) {
    var no = {atomIndex=BBidx}.atomno
    var i = 1
    for (; i < 5; i++) {
        if ({(atomno=@{no+i}) and (chain=gChain)}.atomName == "CB") {
            break
        }
    }
    return {(atomno=@{no+i}) and (chain=gChain)}.atomIndex
}

function get_o_idx (BBidx) {
    var no = {atomIndex=BBidx}.atomno
    var i = 1
    for (; i < 4; i++) {
        if ({(atomno=@{no+i}) and (chain=gChain)}.atomName == "O") {
            break
        }
    }
    return {(atomno=@{no+i}) and (chain=gChain)}.atomIndex
}

function get_nward_bb_no (iNo, iChain) {
    while ((iNo >= 0) and (
        ({(atomno=iNo) and (chain=iChain)}.atomName != "N")
        and ({(atomno=iNo) and (chain=iChain)}.atomName != "C")
        and ({(atomno=iNo) and (chain=iChain)}.atomName != "CA"))) {
        iNo--
    }
    return iNo
}

function get_nward_bb_idx (idx, iChain) {
    var no = {atomIndex=idx}.atomno - 1
    no = get_nward_bb_no( no, iChain)
    return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1)
}

function get_cward_bb_no (iNo, iChain) {
    while ((iNo < gMaxNo) and (
        ({(atomno=iNo) and (chain=iChain)}.atomName != "N")
        and ({(atomno=iNo) and (chain=iChain)}.atomName != "C")
        and ({(atomno=iNo) and (chain=iChain)}.atomName != "CA"))) {
        iNo++
    }
    return iNo
}

function get_cward_bb_idx (idx, iChain) {
    var no = {atomIndex=idx}.atomno + 1
    no = get_cward_bb_no( no, iChain)
    return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1)
}

function get_sc_set (scIdx, iChain) {
    var scSet = ({})
    var idx = get_sc_bb_idx(scIdx, iChain)
    var iNo = {atomIndex=idx}.atomno + 3
    
    for (var i = 1; i < 20; i++) {
        idx = {(atomno=@{iNo+i}) and (chain=iChain)}.atomIndex
        if (is_bb_idx(idx)) {
            break
        }
        scSet = scSet or {atomIndex=idx}
    }
    return scSet
}

function get_sc_bb_idx (idx, iChain) {
    var no = {atomIndex=idx}.atomno
    for (; no > 0; no--) {
        if ({(atomno=no) and (chain=iChain)}.atomName == "CA") {
            break
        }
        else if ({(atomno=no) and (chain=iChain)}.atomName == "C") {
            break
        }
        else if ({(atomno=no) and (chain=iChain)}.atomName == "N") {
            break
        }
        else if ({(atomno=no) and (chain=iChain)}.atomName == "CB") {
            no -= 3
            break
        }
    }
    return {(atomno=no) and (chain=iChain)}.atomIndex
}

function is_bb_idx(aIdx) {
    var ret = FALSE
    switch({atomIndex=aIdx}.atomName) {
    case "N":
    case "CA":
    case "C":
        ret = TRUE
        break
    }
    return ret
}

function is_sc_idx(aIdx) {

    var ret = FALSE
    if (not is_bb_idx(aIDx)) {

        ret = TRUE
        switch({atomIndex=aIdx}.atomName) {
        case "O":
        case "CB":
            ret = FALSE
            break
        }
    }
    return ret
}

function add_sc_to_select(CAno, isAdd, addOXT, iChain) {
    var iNo = CAno+3
    while ({(atomno=iNo) and (chain=iChain)}.resno == {(atomno=CAno) and (chain=iChain)}.resno) {
        {(atomno=iNo) and (chain=iChain)}.selected = isAdd
        if ({(atomno=iNo) and (chain=iChain)}.atomName == "OXT") {
            {(atomno=iNo) and (chain=iChain)}.selected = addOXT
        }
        iNo++
    }
}

function select_add_sc(fromIdx) {
    var iNo = {atomIndex=fromIdx}.atomno
    var iChain = {atomIndex=fromIdx}.chain
    select none
    while ({(atomno=iNo) and (chain=iChain)}.atomName != "N") {
        {(atomno=iNo) and (chain=iChain)}.selected = TRUE
        iNo++
        if (iNo > {chain=iChain}.atomno.max) {
            break
        }
    }
}

# First and last are BB atoms
# Any side atoms in the range are also selected
function select_nward_idx (firstIdx, lastIdx) {
    var firstno = ((firstIdx < 0) ? {atomIndex=lastIdx}.atomno : {atomIndex=firstIdx}.atomno)
    var lastno = ((lastIdx < 0) ? firstno : {atomIndex=lastIdx}.atomno)
    var iChain = ((firstIdx < 0)
        ? {atomIndex=lastIdx}.chain : {atomIndex=firstIdx}.chain)

    select (atomno <= firstno) and (atomno >= lastno) and (chain = iChain)

    if ({(atomno=firstno) and (chain=gChain)}.atomName == "C") { # if psi
        add_sc_to_select(firstno-1, TRUE, TRUE, iChain)
        {(atomno=@{firstno+1}) and (chain=iChain)}.selected = TRUE # add O
    }
    if ({(atomno=firstno) and (chain=iChain)}.atomName == "CA") {
        add_sc_to_select(firstno, TRUE, FALSE, iChain)
    }
    if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi
        add_sc_to_select(lastno-1, FALSE, FALSE, iChain)
    }
}

# First and last are BB atoms
# Any side atoms in the range are also selected
function select_cward_idx (firstIdx, lastIdx) {
    var firstno = ((firstIdx < 0) ? gMaxNo : {atomIndex=firstIdx}.atomno)
    var lastno = ((lastIdx < 0) ? 1 : {atomIndex=lastIdx}.atomno)
    var iChain = ((firstIdx < 0)
        ? {atomIndex=lastIdx}.chain : {atomIndex=firstIdx}.chain)

    # If nWard anchor in range, begin selection with it
    if ((gNanchorIdx >= 0) and ({atomIndex=gNanchorIdx}.chain == iChain))  {
        var aNo = {atomIndex=gNanchorIdx}.atomno
        if (aNo > firstNo) {
            firstno = aNo
        }
    }

    # If cWard anchor in range, end selection with it
    if ((gCanchorIdx >= 0) and ({atomIndex=gCanchorIdx}.chain == iChain))  {
        var aNo = {atomIndex=gCanchorIdx}.atomno
        if (aNo < lastNo) {
            lastno = aNo
        }
    }

    select (atomno >= firstno) and (atomno <= lastno) and (chain = iChain)

    if ({(atomno=firstno) and (chain=iChain)}.atomName == "C") { # if psi
        add_sc_to_select(firstno-1, FALSE, FALSE, iChain)
    }
    if ({(atomno=lastno) and (chain=iChain)}.atomName == "CA") {
        add_sc_to_select(lastno, TRUE, FALSE, iChain)
    }
    if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi
        add_sc_to_select(lastno-1, TRUE, TRUE, iChain)
        {(atomno=@{lastno+1}) and (chain=iChain)}.selected = TRUE # add O
    }
}


# Resolve collisions
function handle_collisions_2( targetIdx) {

    # For all selected atoms
    for (var iNo = {selected}.min.atomno; iNo <= {selected}.max.atomno; iNo++) {
        var idx = {(atomno=iNo) and (chain=gchain)}.atomIndex
        if ({atomindex=idx}.selected) {

            # Collect local colliders
            var lcAtoms = (within(kCtolerance, FALSE, {atomIndex=idx})
                and not {atomIndex=idx}
                and not {gOkCollide}
                and not connected({atomIndex=idx}))
            if (lcAtoms.size > 0) {

                # Ignore kinked BB
                if (is_bb_idx(idx) and angle({atomIndex=@{get_cward_bb_idx(idx, gChain)}},
                    {atomIndex=idx} , {atomIndex=@{get_nward_bb_idx(idx, gChain)}}) < 100) {
                    continue
                }

                # For all local colliders
                for (var c = 1; c <= lcAtoms.size; c++ ) {
                    var cidx = lcAtoms[c].atomIndex

                    # If it is with water, delete it
                    if (lcAtoms[c].group = "HOH") {
                        delete {atomIndex=cidx}
                    }

                    # else if it is with side chain not proline, fix it
                    else if (is_sc_idx(cidx) and ({atomIndex=cidx}.group != "PRO")) {
                        fix_sc_collision_2(cidx)
                        recollect = TRUE

                        # If not fixed, exit fail
                        if (not gOk2) {
                            return # early exit (break n jmol bug)
                        }
                    }

                    # else if it is itself a side chain not proline, fix it
                    else if (is_sc_idx(idx) and ({atomIndex=idx}.group != "PRO")) {
                        fix_sc_collision_2(idx)
                        recollect = TRUE

                        # If not fixed, exit fail
                        if (not gOk2) {
                            return # early exit (break n jmol bug)
                        }
                    }

                    # Else if it is with O, counter-rotate
                    else if (lcAtoms[c].atomName = "O") {
                        counter_rotate_2(lcAtoms[c].atomIndex,
                            {atomIndex=idx}.xyz, targetIdx, FALSE)

                        # If not fixed, exit fail
                        if (not gOk2) {
                            return # early exit (break n jmol bug)
                        }
                    }

                    # Else if it is itself O, counter-rotate
                    else if ({atomIndex=idx}.atomName = "O") {
                        counter_rotate_2(idx, lcAtoms[c].xyz, targetIdx, FALSE)

                        # If not fixed, exit fail
                        if (not gOk2) {
                            return # early exit (break n jmol bug)
                        }
                    }

                    else {    # Else not fixed, exit fail
                        gOk2 = FALSE
                        return # early exit (break n jmol bug)
                    }
                } # endfor
            }
        }
    } # endfor iNo
}

# Rotate rotor set to move target atom to its proper place
function tug_track_idx(targetIdx, targetPt, nWard, cDetect) {
    gOK = FALSE
    var pt = targetPt
    var dist = distance(pt, {atomIndex=targetIdx}.xyz)

    var rotors = (nWard ? gNrotors : gCrotors)

    # For a number of passes
    for (var pass1 = 0; pass1 < 20; pass1++) {
        var blocked = ({})
        for (var pass2 = 0; pass2 < (rotors.size/4); pass2++) {

            var v1 = {atomIndex=targetIdx}.xyz - pt

            # Find the most orthgonal unused rotor
            var imax = 0
            var smax = 0.5
            for (var i = 1; i < rotors.size; i += 4) {
                var i2 = rotors[i+1]
                var i3 = rotors[i+2]
                var i4 = rotors[i+3]
                if ((i2 != targetIdx) and (i3 != targetIdx) and (i4 != targetIdx)) {
                    if ({blocked and {atomIndex=i2}}.count == 0) {
                        var v2 = {atomIndex=i3}.xyz - {atomIndex=i2}.xyz

                        var s = sin(abs(angle(v1, {0 0 0}, v2)))
                        if (s > smax) {
                            smax = s
                            imax = i
                        }
                    }
                }
            }

            # If no more rotors, break to next full try
            if (imax == 0) {
               break
            }
            var i1 = rotors[imax+0]
            var i2 = rotors[imax+1]
            var i3 = rotors[imax+2]
            var i4 = rotors[imax+3]

            # Get dihedral of rotor with target point
            var dt = angle({atomIndex=targetIdx}, {atomIndex=i2}, {atomIndex=i3}, pt)
            var dh = angle({atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}, {atomIndex=i4})
            if (dh == "NaN") {
                dh = -50
            }
            var psi = dh + dt
            var phi = dh + dt

            # Compute resultant psi and phi
            #  and select from target atom to first half of rotor
            var movePt = FALSE
            if (nWard) {
                if ({atomIndex=i2}.atomName="CA") {
                    psi = angle({atomIndex=@{get_cward_bb_idx(i1, gChain)}}, {atomIndex=i1},
                        {atomIndex=i2}, {atomIndex=i3}) + dt
                }
                else {
                    phi = angle({atomIndex=i1}, {atomIndex=i2},
                        {atomIndex=i3}, {atomIndex=@{get_nward_bb_idx(i3, gChain)}}) + dt
                }

                if ({atomIndex=i2}.atomno > {atomIndex=targetIdx}.atomno) {
                    movePt = TRUE
                    select_nward_idx(i3, get_cward_bb_idx(targetIdx, gChain))
                    {atomIndex=targetIdx}.selected = TRUE
                }
                else {
                    select_cward_idx(i2, targetIdx)
                }
            }
            else {
                if (({atomIndex=i2}.atomName="CA")) {
                    phi = angle({atomIndex=@{get_nward_bb_idx(i1, gChain)}}, {atomIndex=i1},
                        {atomIndex=i2}, {atomIndex=i3}) + dt
                }
                else {
                    psi = angle({atomIndex=i2}, {atomIndex=i3},
                        {atomIndex=i4}, {atomIndex=@{get_cward_bb_idx(i4, gChain)}}) + dt
                }

                if ({atomIndex=i2}.atomno < {atomIndex=targetIdx}.atomno) {
                    movePt = TRUE
                    select_cward_idx(i3, get_nward_bb_idx(targetIdx, gChain))
                    {atomIndex=targetIdx}.selected = TRUE
                }
                else {
                    select_nward_idx(i2, targetIdx)
                }
            }

            # Relax rules if desperate
            if (pass1 > 10) {
                phi = -50
            }

            # If rotation within ramachandran limits
            if ((abs(dt) >= 0.1) and
                (({atomIndex=i2}.group=="GLY") or (phi < 0))) {

                # If moving target point, put the target atom there
                var cp = {atomIndex=targetIdx}.xyz
                if (movePt) {
                    dt = -dt
                    {atomIndex=targetIdx}.xyz = pt
                }

                # Rotate to minimize vector ====================
                rotateSelected {atomIndex=i2} {atomIndex=i3} @dt

                # If collision checking
                if (cDetect) {

                    # If collision, back off by eighths
                    var wasCollision = FALSE
                    for (var ci = 0; ci < 4; ci++) {
                        if (ci < 3) {
                            dt /= 2
                        }
                        handle_collisions_2( targetIdx)
                        if (not gOk2) {
                            wasCollision = TRUE
                            rotateSelected {atomIndex=i2} {atomIndex=i3} @{-dt}
                        }
                        else if (wasCollision) {
                            if (ci <3) {
                                rotateSelected {atomIndex=i2} {atomIndex=i3} @{dt}
                            }
                        }
                        else {
                            break
                        }

                        if (dt < 0.01) {
                            break
                        }
                    } # endfor
                }

                # If moving target point, put the target atom back
                if (movePt) {
                    pt = {atomIndex=targetIdx}.xyz
                    {atomIndex=targetIdx}.xyz = cp
                }

            }

            # If close enough, stop
            if (distance(pt, {atomIndex=targetIdx}) < kDtolerance) {
                gOK = TRUE
                gTargetPt = pt
                break
            }

            # Block rotor
            blocked |= {atomIndex=i2}

        }   # endfor num rotors passes

        if (gOK) {
            break
        }
    }   # endfor 20 passes
}

# Counter rotate bonds on either side of a BB O
function do_counter_rotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nWard) {

    # Rotate psi
    {atomIndex=nIdx}.selected = nWard
    {atomIndex=cIdx}.selected = nWard
    {atomIndex=oIdx}.selected = nward
    rotateSelected {atomIndex=caPsiIdx} {atomIndex=cIdx} @{dir}

    # Counter-rotate phi
    {atomIndex=nIdx}.selected = not nWard
    {atomIndex=cIdx}.selected = not nWard
    {atomIndex=oIdx}.selected = not nward
    rotateSelected {atomIndex=nIdx} {atomIndex=caPhiIdx} @{-dir}
}

function counter_rotate(oIdx, dir, nWard) {

    var iChain = {atomIndex=oIdx}.chain
    var selsave = {selected}
    var cIdx = get_sc_bb_idx(oIdx, iChain)
    var nIdx = get_cward_bb_idx(cIdx, iChain)
    var caPhiIdx = get_cward_bb_idx(nIdx, iChain)
    var caPsiIdx = get_nward_bb_idx(cIdx, iChain)

    if (nWard) {
        nNo = {chain=iChain}.atomno.min
        select_nward_idx(caPsiIdx, {(atomno=nNo) and (chain=iChain)}.atomIndex)
    }
    else {
        cNo = {chain=iChain}.atomno.max
        select_cward_idx(caPhiIdx, {(atomno=cNo) and (chain=iChain)}.atomIndex)
    }

    # Counter-rotate
    do_counter_rotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, not nWard)
    select selsave
}

function counter_rotate_2(oIdx, toPt, terminalIdx, oDrag) {

    var iChain = {atomIndex=oIdx}.chain
    var selsave = {selected}
    var gOk2 = TRUE
    var cIdx = get_sc_bb_idx(oIdx, iChain)
    var nIdx = get_cward_bb_idx(cIdx, iChain)
    var caPhiIdx = get_cward_bb_idx(nIdx, iChain)
    var caPsiIdx = get_nward_bb_idx(cIdx, iChain)

    var nTward = ({atomIndex=oIdx}.atomno < {atomIndex=terminalIdx}.atomno)
    if (nTward) {
        select_cward_idx(cIdx, terminalIdx)
    }
    else {
        select_nward_idx(nIdx, terminalIdx)
    }

    # Until all collisions cancelled
    var dir = 5
    var ang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx})
    var tcount = 0
    while (oDrag or (within(kCtolerance, FALSE, {atomIndex=oIdx})
            and not {atomIndex=oIdx} and not connected({atomIndex=oIdx})
            and not {gOkCollide} > 0)) {

        # Counter-rotate
        do_counter_rotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nTward)
        var newang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx})

        # If wrong direction once, undo and reverse
        if (newang > ang) {
            do_counter_rotate(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, -dir, nTward)

            # If first time, continue in opposite direction
            dir *= -1
            if (dir < 0) {
                continue
            }
        }

        if (oDrag) {
            break
        }

        # If no go, undo and exit
        tcount++
        if (tcount > (360/abs(dir))) {
            gOk2 = FALSE
            break
        }

    } # endwhile
    select selsave
}

# Repair proline
function repair_proline(BBidx) {
    var cbidx = get_cb_idx(BBidx)
    var cbno = {atomIndex=cbidx}.atomno
    var cgidx = {(atomno=@{cbno+1}) and (chain=gChain)}.atomIndex
    var cdidx = {(atomno=@{cbno+2}) and (chain=gChain)}.atomIndex
    var caidx = {(atomno=@{cbno-3}) and (chain=gChain)}.atomIndex
    var nidx = {(atomno=@{cbno-4}) and (chain=gChain)}.atomIndex

    select {atomIndex=cbidx}
    set_angle_idx(nidx, caidx, cbidx, 109.5)

    select {atomIndex=cdidx}
    set_distance_idx(nidx, cdidx, 1.47)
    set_angle_idx(caidx, nidx, cdidx, 102.7)
    set_dihedral_idx(cbidx, caidx, nidx, cdidx, 16.2)

    select {atomIndex=cgidx}
    set_distance_idx(cdidx, cgidx, 1.51)
    set_angle_idx(nidx, cdidx, cgidx, 106.4)
    set_dihedral_idx(caidx, nidx, cdidx, cgidx, 16.2)
}

# Repair side chain
function repair_sc(targetIdx, nWard) {

    var idx = (nWard ? get_cward_bb_idx(targetIdx, gChain) : get_nward_bb_idx(targetIdx, gChain))

    if (({atomIndex=targetIdx}.atomName == "CA")
        and ({atomIndex=targetIdx}.group != "GLY")) {
        var cbidx = get_cb_idx(targetIdx)
        select none
        select_add_sc(cbidx)
        set_angle_idx(idx, targetIdx, cbidx, 110.0)
        set_distance_idx(targetIdx, cbidx, 1.5)
        if ({atomIndex=targetIdx}.group != "PRO") {
            var colliders = (within(kCtolerance, FALSE, {selected})
                and not {atomIndex=targetIdx} and not {selected})
            if (colliders.size > 0) {
                if ({atomIndex=targetIdx}.group != "ALA") {
                    fix_sc_collision_2(cbidx)
                }
            }
        }
        else {
            if (nWard) {
            }
            else {
                set_dihedral_idx(get_nward_bb_idx(idx, gChain), idx, targetIdx, cbidx, 174.2)
            }
        }
    }

    else if ({atomIndex=targetIdx}.atomName == "C") {
        var oidx = get_o_idx(targetIdx)
        select {atomIndex=oidx}
        set_angle_idx(idx, targetIdx, oidx, 120.0)
        set_distance_idx(targetIdx, oidx, 1.21)
        if (nWard) {
            set_dihedral_idx(get_cward_bb_idx(idx, gChain), idx, targetIdx, oidx, 0.0)
        }
        if ({atomIndex=idx}.group == "PRO") {
            repair_proline(idx)
            var dNo = {atomIndex=targetIdx}.atomno + 4
            var dIdx = {(atomno=dNO) and (chain=gChain)}.atomIndex
            var colliders = (within(kCtolerance, FALSE, {atomIndex=dIdx})
                and not connected({atomIndex=dIdx})
                and not {atomIndex=dIdx})
            for (var i = 1; i <= colliders.size; i++) {
                if (colliders[i].atomName == "O") {
                    counter_rotate_2(colliders[i].atomIndex,
                        {atomIndex=dIdx}.xyz, targetIdx, FALSE)
                }
            }
        }
    }
}

# Rebuild Cward rotors set
function tug_track_c() {

    # For all bb atoms cWard of cargo
    var targetIdx = gCcargoIdx
    var okCount = 0

    # Allow collisions with cargo
    gOkCollide = gCargoSet
    var tcount = 0
    while (targetIdx != gCanchorIdx) {

        # Step to next atom
        targetIdx = get_cward_bb_idx(targetIdx, gChain)

        # No collision with cargo allowed after two atoms placed
        if (tcount == 2) {
           gOkCollide = ({})
        }
        tcount++

        # Compute targets desired coords
        var c1idx = get_cward_bb_idx(targetIdx, gChain)
        var n1idx = get_nward_bb_idx(targetIdx, gChain )
        var n2idx = get_nward_bb_idx(n1Idx, gChain)
        var n3idx = get_nward_bb_idx(n2Idx, gChain)
        var pt = {0 0 0}
        if ({atomIndex=targetIdx}.atomName == "N") {
            var oidx = get_o_idx(n1idx)
            select {atomIndex=oidx}

            # Desired target location is trigonal O
            set_distance_idx(n1idx, oidx, 1.5)
            pt = get_trigonal_idx(n2idx, n1idx, oidx, 1.37)
            set_distance_idx(n1idx, oidx, 1.21)
        }
        else if (({atomIndex=targetIdx}.atomName == "C")
            and ({atomIndex=targetIdx}.group != "GLY")) {

            # Desired target location is tetragonal CB
            var cbidx = get_cb_idx(n1idx)
            pt = get_tet_idx(n2idx, n1idx, cbidx, 1.5)
        }
        else { # CA (or GLY C)

            # Save current target coords
            var cp = {atomIndex=targetIdx}.xyz

            # Set target atom at desired distance and angle
            select {atomIndex=targetIdx}
            set_distance_idx(n1idx, targetIdx, 1.5)
            set_angle_idx(n2idx, n1idx, targetIdx, 120.0)
            if ({atomIndex=targetIdx}.atomName == "CA") {
                set_dihedral_idx(n3idx, n2idx, n1idx, targetIdx, 180)
            }

            # Record and restore target
            pt = {atomIndex=targetIdx}.xyz
            {atomIndex=targetIdx}.xyz = cp
        }

        # If target not at desired location
        if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) {
            okCount = 0
            gTargetPt = pt
            var xcount = 0
            gOK = FALSE
            while ((xcount < 20) and (not gOK)) {

                # Rotate on cWard rotor set to move it there
                tug_track_idx(targetIdx, pt, FALSE, FALSE)
                xcount++
            }
        }
        else {
            gOK = TRUE
            okCount++
        }

        # If successful
        if (gOK == TRUE) {

            # Adust any side atoms
            repair_sc(targetIdx, FALSE)
        }

        # Else fail
        else {
            break
        }

        # If no movement in 4 tries, we are done
        if (okCount > 3) {
            break
        }
    } # endwhile (targetIdx != gCanchorIdx) {
}

# Rebuild Nward rotors set
function tug_track_n() {

    gOK = TRUE

    # For all bb atoms nWard of cargo
    var targetIdx = gNcargoIdx
    var okCount = 0

    # Allow collisions with cargo
    gOkCollide = gCargoSet
    var tcount = 0
    while (targetIdx != gNanchorIdx) {

        # Step to next atom
        targetIdx = get_nward_bb_idx(targetIdx, gChain)

        # No collision with cargo allowed after two atoms placed
        if (tcount == 2) {
           gOkCollide = ({})
        }
        tcount++

        # Compute targets desired coords
        var n1idx = get_nward_bb_idx(targetIdx, gChain)
        var c1idx = get_cward_bb_idx(targetIdx, gChain)
        var c2idx = get_cward_bb_idx(c1idx, gChain)
        var c3idx = get_cward_bb_idx(c2idx, gChain)
        var pt = {0 0 0}
        if ({atomIndex=targetIdx}.atomName == "CA") {

            # Desired target location is trigonal O
            var oidx = get_o_idx(c1idx)
            select {atomIndex=oidx}
            set_distance_idx(c1idx, oidx, 1.39)
            pt = get_trigonal_idx(c2idx, c1idx, oidx, 1.41)
            set_distance_idx(c1idx, oidx, 1.21)
        }
        else if (({atomIndex=targetIdx}.atomName == "N")
            and ({atomIndex=targetIdx}.group != "GLY")) {

            # Desired target location is r-tetragonal CB
            var cbidx = get_cb_idx(c1idx)
            pt = get_tet_idx(cbidx, c1idx, c2idx, 1.5)
        }
        else { # C

            # Save current target coords
            var cp = {atomIndex=targetIdx}.xyz

            # Set target atom at desired distance and angle
            select {atomIndex=targetIdx}
            set_distance_idx(c1idx, targetIdx, 1.37)
            set_angle_idx(c2idx, c1idx, targetIdx, 110.0)

            if ({atomIndex=targetIdx}.group == "PRO") {
                set_dihedral_idx(c3idx, c2idx, c1idx, targetIdx, -57.0)
            }

            # Record and restore target
            pt = {atomIndex=targetIdx}.xyz
            {atomIndex=targetIdx}.xyz = cp
        }

        # If target not at desired location
        if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) {
            var okCount = 0
            gTargetPt = pt
            var xcount = 0
            gOK = FALSE
            while ((xcount < 20) and (not gOK)) {

                # Rotate on nWard rotor set to move it there
                tug_track_idx(targetIdx, pt, TRUE, FALSE)
                xcount++
            }
        }
        else {
            gOK = TRUE
            okCount++
        }

        # If sucessful
        if (gOK == TRUE) {

            # Adust any side atoms
            repair_sc(targetIdx, TRUE)
        }

        # Else fail
        else {
            break
        }

        # If no movement in 4 tries, we are done
        if (okCount > 3) {
            break
        }

    }   # endwhile (targetIdx != gNanchorIdx) {
}

# gPlicoRecord is maintained by the macro pilcoRecord
function plico_record(s) {
    var g = format("show file \"%s\"", gPlicoRecord)
    var ls = script(g)
    if (ls.find("FileNotFoundException")) {
        ls = ""
    }
    ls += s
    write var ls @gPlicoRecord
}

# gPlicoRecord is maintained by the macro pilcoRecord
function translate_selected_record(pt) {
    if (gPlicoRecord != "") {
        plico_record(format("select %s;translateSelected %s;", {selected}, pt))
    }
    translateSelected @pt
}

# gPlicoRecord is maintained by the macro pilcoRecord
function rotate_selected_record(pivotIdx, axis, a) {
    if (gPlicoRecord != "") {
        plico_record(format("select %s;", {selected}))
        plico_record(format("rotateSelected {atomIndex=%d} @%s @%s;",
            pivotIdx, axis, a))
    }
    rotateSelected {atomIndex=pivotIdx} @axis @a
}

function collect_sc_rotors(no, iChain) {
    var scBondIdxs = array()
    for (var iNo = no; iNo >= 0; iNo--) {
        var ile = 0
        switch ({(atomno=iNo) and (chain=iChain)}.atomName) {
        case "CA" :
            return scBondIdxs # Early exit since break 1 appears broken
        case "CZ" :
            if ({(atomno=iNo) and (chain=iChain)}.group == "TYR") {
                break
            }
        case "CE" :
            if ({(atomno=iNo) and (chain=iChain)}.group == "MET") {
                break
            }
        case "CG1" :
            if ({(atomno=iNo) and (chain=iChain)}.group == "VAL") {
                break
            }
            if ({(atomno=iNo) and (chain=iChain)}.group == "ILE") {
                ile = 1
            }
        case "NE" :
        case "CD" :
        case "SD" :
        case "CG" :
        case "CB" :
            scBondIdxs += {(atomno=@{iNo+1+ile}) and (chain=iChain)}.atomIndex
            scBondIdxs += {(atomno=@{iNo+0}) and (chain=iChain)}.atomIndex
            if ({(atomno=iNo) and (chain=iChain)}.atomName%2 == "CG") {
                scBondIdxs += {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex
                scBondIdxs += {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex
            }
            else if ({(atomno=iNo) and (chain=iChain)}.atomName == "CB") {
                scBondIdxs += {(atomno=@{iNo-3}) and (chain=iChain)}.atomIndex
                scBondIdxs += {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex
            }
            else {
                scBondIdxs += {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex
                scBondIdxs += {(atomno=@{iNo-2}) and (chain=iChain)}.atomIndex
            }
            break
        }

    }

    return scBondIdxs
}

# Drag Side Chain
function drag_sc() {

    var iNo = {atomIndex=gSCidx}.atomno
    var iChain  = {atomIndex=gSCidx}.chain

    if ({atomIndex=gSCidx}.group != "PRO") {

        var scBondIdxs = collect_sc_rotors( iNo, iChain)
        var numChi = scBondIdxs.size / 4
        var dist = distance({atomIndex=gSCidx}.xyz, gSCpt)

        var scSet = ({})
        if (gSCcheck) {
            scSet = get_sc_set(gSCidx, iChain)
        }
        
        # For all rotor combinations
        var dh = array()
        for (var i = 0; i < numChi; i++) {
            dh += angle({atomIndex=@{scBondIdxs[4+(4*i)]}},
                {atomIndex=@{scBondIdxs[3+(4*i)]}},
                {atomIndex=@{scBondIdxs[2+(4*i)]}},
                {atomIndex=@{scBondIdxs[1+(4*i)]}})
        }
        for (var i = 0; i < numChi; i++) {
            var rot = -120
            for (var j = 0; j < 6; j++) {
                rot += 60*j
                select_add_sc(scBondIdxs[1+(4*i)])
                set_dihedral_idx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)],
                    scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], rot)
                var newDist = distance({atomIndex=gSCidx}.xyz, gSCpt)
                if (gSCcheck) {
                    var colliders = (within(kCtolerance, FALSE, scSet)
                        and not connected(scSet) and not {scSet})
                    if (colliders.size > 0) {
                        continue
                    }
                }
                
                # Find the best
                if (newDist < dist) {
                    dist = newDist
                    for (var k = 0; k < numChi; k++) {
                        dh[k+1] = angle({atomIndex=@{scBondIdxs[4+(4*k)]}},
                        {atomIndex=@{scBondIdxs[3+(4*k)]}},
                        {atomIndex=@{scBondIdxs[2+(4*k)]}},
                        {atomIndex=@{scBondIdxs[1+(4*k)]}})
                    }
                }
            }
        }

        # Now set the best
        for (var i = 0; i < numChi; i++) {
            select_add_sc(scBondIdxs[1+(4*i)])
            set_dihedral_idx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)],
                scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], dh[i+1])
        }
    }
    else { # PRO - toggle between puckers up and down
        var icd = {(atomno=@{iNo+1}) and (chain=iChain)}.atomIndex
        var icb = {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex
        var ica = {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex
        var in = {(atomno=@{iNo-5}) and (chain=iChain)}.atomIndex
        select {atomIndex=gSCidx}

        if (angle({atomIndex=ica}, {atomIndex=in},
            {atomIndex=icd}, {atomIndex=gSCidx}) < -10.0) {
            set_dihedral_idx(ica, in, icd, gSCidx, 8.7)
            set_angle_idx(in, icd, gSCidx, 110.0)
            set_distance_idx(icd, gSCidx, 1.5)
        }
        else {
            set_dihedral_idx(ica, in, icd, gSCidx, -29.5)
            set_angle_idx(in, icd, gSCidx, 108.8)
            set_distance_idx(icd, gSCidx, 1.5)
        }
    }

    draw gSCcircle CIRCLE {atomIndex=gSCidx} MESH NOFILL
    gSCpt = {atomIndex=gSCidx}.xyz
}

# Fix side chain collisions
function fix_sc_collision_2(idx) {
    gOk2 = FALSE
    var iNo = {atomIndex=idx}.atomno
    var iChain = {atomIndex=idx}.chain
    var resno = {(atomno=iNo) and (chain=iChain)}.resno

    # Get SC terminus
    while (resno == {(atomno=iNo) and (chain=iChain)}.resno) {
        iNo++
    }
    iNo--

    var sc = array()
    var iBno = iNo
    while ({(atomno=iBno) and (chain=iChain)}.atomName != "CB") {
        sc += {(atomno=iBno) and (chain=iChain)}
        iBno--
    }
    var cbidx = {(atomno=iBno) and (chain=iChain)}.atomIndex

    var scBondIdxs = collect_sc_rotors( iNo, iChain)
    var numChi = scBondIdxs.size / 4

    # For all rotor combinations
    for (var i = 0; i < numChi; i++) {
        var rot = -120
        for (var j = 0; j < 6; j++) {
            rot += 60
            select_add_sc(scBondIdxs[1+(4*i)])
            set_dihedral_idx(scBondIdxs[1+(4*i)], scBondIdxs[2+(4*i)],
                scBondIdxs[3+(4*i)], scBondIdxs[4+(4*i)], rot)
                
            # If no collision, exit
            colliders = (within(kCtolerance, FALSE, {sc})
                and not {atomIndex=cbidx} and not {sc})

            # If it is with water, delete the water
            for (var c = 1; c < colliders.size; c++ ) {
                if (colliders[c].group = "HOH") {
                    delete {atomIndex=@{colliders[c].atomIndex}}
                    colliders = {colliders and not @{colliders[c]}}
                }
            }

            if (colliders.size == 0) {
                gOk2 = TRUE
                return # Early exit since break 1 appears broken
            }

        }
    }
}

function is_moveable_sc(aIdx) {

    var ret = (({atomIndex=aIdx}.group != "PRO")
        or ({atomIndex=aIdx}.atomName == "CG"))
    switch({atomIndex=aIdx}.atomName) {
    case "N":
    case "CA":
    case "C":
    case "CB":
    case "O":
    case "O4\'":
        ret = FALSE
        break
    }
    return ret
}

function is_rotor_avail(i1idx, i2idx) {
    var ret = TRUE
    if (i1idx > i2idx) {
        var idx = @i1idx
        i1idx = @i2idx
        i2idx = @idx
    }
    
    for (var i = 1; i <= gFreeze.size; i += 2) {
        if ((gFreeze[i] == i1idx) and (gFreeze[i+1] == i2idx)) {
            ret = FALSE
            break
        }
    }
    
    return ret
}

function collect_bb_rotors(nWard) {
    var anchorNo = (nWard
        ? ((gNanchorIdx >= 0) ? {atomIndex=gNanchorIdx}.atomno : gMinNo)
        : ((gCanchorIdx >= 0) ? {atomIndex=gCanchorIdx}.atomno : gMaxNo))
    var cargoNo = (nWard
        ? ((gNcargoIdx >= 0) ? {atomIndex=gNcargoIdx}.atomno
        : {atomIndex=gCcargoIdx}.atomno)
        : {atomIndex=gCcargoIdx}.atomno)
    var rotors = array()
    if (cargoNo < anchorNo) {

        for (var iNo = cargoNo; iNo <= anchorNo; iNo++) {
            if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") {
                if (is_rotor_avail(iNo)) {
                    if (({(atomno=iNo) and (chain=gChain)}.group != "PRO") and (iNo > cargoNo)) { # phi
                        rotors += [{(atomno=@{get_cm_no(iNo-1)}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex]
                        rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex]
                    }
                    if (iNo != (anchorNo-1)) { # psi
                        rotors += [{(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{iNo}) and (chain=gChain)}.atomIndex]
                        rotors += [{(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{get_np_no(iNo+2)}) and (chain=gChain)}.atomIndex]
                    }
                }
            }
        }
    }
    else {

        for (var iNo = cargoNo; iNo >= anchorNo; iNo--) {
            if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") {
                if (is_rotor_avail(iNo)) {
                    if ((iNo != (anchorNo-1)) and (iNo < cargoNo)) { # psi
                        rotors += [{(atomno=@{get_np_no(iNo+2)}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex]
                        rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex]
                    }
                    if ({(atomno=iNo) and (chain=gChain)}.group != "PRO") { # phi
                        rotors += [{(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{iNo}) and (chain=gChain)}.atomIndex]
                        rotors += [{(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex,
                            {(atomno=@{get_cm_no(iNo-1)}) and (chain=gChain)}.atomIndex]
                    }
                }
            }
        }
    }

    if (nWard) {
        gNrotors = rotors
    }
    else {
        gCrotors = rotors
    }
}

function collect_rotors() {
    collect_bb_rotors(FALSE)
    collect_bb_rotors(TRUE)
}

function tug_sc(pt) {

    # If destination atom defined
    if (gDestAtomIdx >= 0) {
        var v = {atomIndex=gDestAtomIdx}.xyz - {atomIndex=gSCidx}.xyz
        if (abs(angle({atomIndex=gDestAtomIdx}.xyz, {0 0 0}, pt)) < 90) {
            pt = -v/20.0
        }
        else {
            pt = v/20.0
        }
    }
    gSCpt += pt
    draw arrow {atomIndex=gSCidx} @gSCpt
}

function set_colors() {
    select all
    color {selected} @gScheme
    color {atomIndex=g1pivotIdx} green
    color {atomIndex=g2pivotIdx} green
    color @gCargoSet @gAltScheme
    select {(atomIndex=gCcargoIdx) or (atomIndex=gNcargoIdx)
        or (atomIndex=gCanchorIdx) or (atomIndex=gNanchorIdx)}
    halo on
    select {atomIndex=gDestAtomIdx}
    star on
    select none
}

function clear_atom_idxs() {
    gCcargoIdx = -1
    gNcargoIdx = -1
    gCanchorIdx = -1
    gNanchorIdx = -1
    g1pivotIdx = -1
    g2pivotIdx = -1
    g1dynamicIdx = -1
    g2dynamicIdx = -1
    gDestAtomIdx = -1
    gSCidx = -1
}

function timed_out (s) {
    timeout ID"tug" OFF
    p = prompt(format("%s - Undo?", s), "Yes|No", TRUE)
    if (p == "Yes") {
        gBusy = FALSE
        background ECHO yellow
        restore state gState
        connect
        select gCargoSet
        refresh
        quit
    }
}

function record_drag() {
    var ls = format("select %s;", {selected})
    ls += format("gCanchorIdx = %d;", gCanchorIdx)
    ls += format("gCanchorNo = %d;", gCanchorNo)
    ls += format("gNanchorIdx = %d;", gNanchorIdx)
    ls += format("gNanchorNo = %d;", gNanchorNo)
    ls += format("gCcargoIdx = %d;", gCcargoIdx)
    ls += format("gNcargoIdx = %d;", gNcargoIdx)
    ls += format("gCcargoNo = %d;", gCcargoNo)
    ls += format("gNcargoNo = %d;", gNcargoNo)
    ls += format("gDestAtomIdx = %d;", gDestAtomIdx)
    ls += format("g1pivotIdx = %d;", g1pivotIdx)
    ls += format("g2pivotIdx = %d;", g2pivotIdx)
    ls += format("gOkCollide = %s;", gOkCollide)
    ls += format("gChain = \"%s\";", gChain)
    ls += format("gMinNo = %d;", gMinNo)
    ls += format("gMaxNo = %d;", gMaxNo)
    ls += format("gCargoSet = %s;", gCargoSet)
    ls += format("gSCidx = %d;", gSCidx)
    ls += format("gSCcircle = %d;", gSCcircle)
    ls += format("gSCpt = %s;", gSCpt)
    ls += "collect_rotors();"
    ls += "tug_drag_done_mb();"
    plico_record(ls)
}

# Pick call-back for freeze
function tug_pick_cb() {

    if (_pickInfo[3][6] == "bond") {
        var sel = {selected}
        var i = _pickInfo.find(":")
        var iChain = _pickInfo[i+1]
        i = _pickInfo.find("#")
        var a1no = _pickInfo[i+1][i+3]
        j = _pickInfo[i+1][9999].find("#")
        var a2no = _pickInfo[i+j+1][i+j+3]
        var i1idx = {(atomno=a1no) and (chain=iChain)}.atomIndex
        var i2idx = {(atomno=a2no) and (chain=iChain)}.atomIndex
        
        if (({atomIndex=i1idx}.atomName == "CA")
            or ({atomIndex=i2idx}.atomName == "CA")) {
            if (({atomIndex=i1idx}.atomName != "CB")
                and ({atomIndex=i2idx}.atomName != "CB")) {
                if (i1idx > i2idx) {
                    idx = 0 + i1idx
                    i1idx = 0 + i2idx
                    i2idx = 0 + idx
                }
                select {atomIndex=i1idx} or {atomIndex=i2idx}
                
                for (i = 1; i <= gFreeze.size; i += 2) {
                    if ((gFreeze[i] == i1idx) and (gFreeze[i+1] == i2idx)) {
                        gFreeze[i] == -1
                        color bonds NONE
                        break
                    }
                }
                if (i > gFreeze.size) {
                    gFreeze += i1idx
                    gFreeze += i2idx
                    color bonds lightblue
                }
            }
        }
        select {sel}
    }
}

# Bound to LEFT-UP by tug_enable_drag
function tug_drag_done_mb() {
    if (not gBusy) {
        if (gPlicoRecord != "") {
            record_drag()
        }

        # Move by rotation on rotor sets, smallest first
        gBusy = TRUE
        background ECHO pink
        refresh

        # If side chain mode
        if (gSCidx >= 0) {
            drag_sc()
        }

        # Else
        else if (not gTow) {
            gOK = TRUE
            timeout ID"tug" 20.0 "timed_out(\"Tug timed out\")"
            if ((gCrotors.size < gNrotors.size) or (gNanchorIdx < 0)) {
                if (gCrotors.size > 4) {
                    tug_track_c()
                }
                if (gOK and (gNrotors.size > 4)) {
                    tug_track_n()
                }
            }
            else {
                if (gNrotors.size > 4) {
                    tug_track_n()
                }
                if (gOK and (gCrotors.size > 4)) {
                    tug_track_c()
                }
            }
            timeout ID"tug" OFF

            # If anchor angles acute, fail
            if (gOK == TRUE) {
                if (gCanchorIdx >= 0) {
                    var ic = get_cward_bb_idx(gCanchorIdx, gChain)
                    var in = get_nward_bb_idx(gCanchorIdx, gChain)
                    if ((ic >= 0) and
                        angle({atomIndex=ic}, {atomIndex=gCanchorIdx}, {atomIndex=in})
                        < 100.0) {
                        gOK = FALSE
                    }
                }
                if (gNanchorIdx >= 0) {
                    var ic = get_cward_bb_idx(gNanchorIdx, gChain)
                    var in = get_nward_bb_idx(gNanchorIdx, gChain)
                    if ((in >= 0) and
                        angle({atomIndex=ic}, {atomIndex=gNanchorIdx}, {atomIndex=in})
                        < 100.0) {
                        gOK = FALSE
                    }
                }
            }

            # If too far
            if (not gOK) {
                timed_out("TUG TOO FAR!")
            }

            # Else OK
            else {

                select ((atomno >= gNanchorNo) and (atomno <= gCanchorNo)
                    and (chain = gChain))
                var idx = {(atomno=@{{chain=gChain}.atomno.min})
                    and (chain=gChain)}.atomIndex


                var ihc = 0
                for (ihc = 0; ihc < 10; ihc++) {
                    handle_collisions_2( idx)
                    if (count_collisions(({})).size == 0) {
                        break
                    }
                }
                if (ihc == 10) {
                    timed_out("Unable to handle all collisions!")
                }
            }
        }
        select {gCargoSet}
        gBusy = FALSE
        background ECHO yellow
        refresh
    }
}

# Bound to ALT-SHIFT-LEFT-DRAG by tug_enable_drag
function tug_drag_2_mb() {
    tug_drag_mb(TRUE)
}

# Bound to ALT-LEFT-DRAG by tug_enable_drag
function tug_drag_mb(alt) {
    if (not gBusy) {
        gBusy = TRUE
        var dx = (40.0 * (_mouseX - gMouseX))/_width
        var dy = (40.0 * (_mouseY - gMouseY))/_height
        var q = quaternion()
        var ptd = {@dx @dy 0}
        var pt = (!q)%ptd
        var axis = {0 0 0}
        if (distance(pt,  {0 0 0}) > 0.004) {
            # If sidechain mode
            if (gSCidx >= 0) {
                if ({atomIndex=gSCidx}.atomName == "O") {
                    dir = ((abs(dx) > abs(dy))
                        ? ((dx < 0) ? 10 : -10)
                        : ((dy < 0) ? 1 : -1))
                    counter_rotate(gSCidx, dir, not alt)
                }
                else {
                    gSCcheck = not alt
                    tug_sc(pt)
                }
            }

            # Else
            else {

                # If new drag
                if (gNewDrag) {
                    gNewDrag = FALSE
                    save state gState
                }

                # If destination atom defined
                if (gDestAtomIdx >= 0) {
                    var v = {atomIndex=gDestAtomIdx}.xyz - {selected}.xyz
                    if (abs(angle({atomIndex=gDestAtomIdx}.xyz, {0 0 0}, pt)) < 90) {
                        pt = -v/20.0
                    }
                    else {
                        pt = v/20.0
                    }
                }

                # Move the cargo
                select {gCargoSet}

                # If pivots defined, rotate it
                if (g1pivotIdx >= 0) {

                    # If two pivots
                    if (g2pivotIdx >= 0) {
                        axis = {atomIndex=g2pivotIdx}
                    }

                    # Else
                    else {
                        axis = cross(pt, {0 0 0}) + {atomIndex=g1pivotIdx}.xyz
                    }

                    dir = ((abs(dx) > abs(dy))
                        ? ((dx < 0) ? 2 : -2)
                        : ((dy < 0) ? 2 : -2))
                    rotate_selected_record(g1pivotIdx, axis, dir)

                }

                # Else translate it
                else {
                    translate_selected_record(pt)
                }

                # If collisions
                var cNotSels = (within(kCtolerance, FALSE, {selected})
                    and not {gMovingSet})
                if ((cNotSels.size > 0) and (not alt)) {
                    gOk2 = TRUE
                    for (var i = 1; i <= cNotSels.size;  i++) {

                        # If net collision vector same as move vector
                        cSels = (within(kCtolerance, FALSE, cNotSels[i]) and {selected})
                        for (var j = 1; j <= cSels.size;  j++) {
                            var v1 = cNotSels[i].xyz - cSels[j].xyz
                            if (abs(angle(v1, {0 0 0}, pt)) < 90) {

                                # If tow mode
                                if (gTow) {

                                    # Make a dynamic pivot
                                    if (g1pivotIdx < 0) {
                                        g1pivotIdx = cSels[j].atomIndex
                                        g1dynamicIdx = cNotSels[i].atomIndex
                                        color {atomIndex=g1pivotIdx} lightgreen
                                        set_distance_idx(cNotSels[i].atomIndex,
                                            cSels[j].atomIndex,
                                            kCtolerance + kDtolerance)
                                    }
                                    else if (g2pivotIdx < 0) {
                                        g2pivotIdx = cSels[j].atomIndex
                                        g2dynamicIdx = cNotSels[i].atomIndex
                                        color {atomIndex=g2pivotIdx} lightgreen
                                        set_distance_idx(cNotSels[i].atomIndex,
                                            cSels[j].atomIndex,
                                            kCtolerance + kDtolerance)
                                    }
                                    else {
                                        gOk2 = FALSE
                                    }
                                }
                                else {

                                    # Try to resolve
                                    select cSels[j]
                                    var idx = {(atomno=@{{chain=gChain}.atomno.min})
                                        and (chain=gChain)}.atomIndex
                                    handle_collisions_2( idx)
                                }
                            }
                        } # endfor
                        if (not gOk2) {
                            break
                        }
                    } # endfor

                    # If unable
                    if (not gOk2) {

                        # Back off
                        background ECHO pink
                        delay 1
                        if (g1pivotIdx >= 0) {
                            rotate_selected_record(g1pivotIdx, axis, -a)
                        }
                        else {
                            translate_selected_record(-pt)
                        }
                        background ECHO yellow
                    }
                }
            }

            # If dynamic pivots
            if (g1dynamicIdx >= 0) {
                var v1 = {atomIndex=g1dynamicIdx}.xyz - {atomIndex=g1pivotIdx}.xyz
                if (abs(angle(v1, {0 0 0}, pt)) > 90) {
                    color {atomIndex=g1pivotIdx} @gAltScheme
                    g1pivotIdx = -1
                    g1dynamicIdx = -1

                }
            }
            if (g2dynamicIdx >= 0) {
                var v1 = {atomIndex=g2dynamicIdx}.xyz - {atomIndex=g2pivotIdx}.xyz
                if (abs(angle(v1, {0 0 0}, pt)) > 90) {
                    color {atomIndex=g2pivotIdx} @gAltScheme
                    g2pivotIdx = -1
                    g2dynamicIdx = -1
                }
            }

            gMouseX = _mouseX
            gMouseY = _mouseY
        }
        select {gCargoSet}
        gBusy = FALSE
    }
}

# Bound to ALT-LEFT-DOWN by tug_enable_drag
function tug_mark_mb() {
    gMouseX = _mouseX
    gMouseY = _mouseY
    gNewDrag = TRUE
}

# Called by tug_cargo_mb
function tug_enable_drag() {
    gEcho = "__________TUG__________|ALT-CLICK=mark block|SHIFT-CLICK=anchors" +
        "|ALT-CTRL-CLICK=pivots|ALT-SHIFT-CLICK=dest atom|ALT-DRAG=move" +
        "|SHIFT-ALT-DRAG=alt move|CLICK bond=freeze|DOUBLE-CLICK=exit"
    echo @gEcho

    # Allow atoms to be dragged
    bind "ALT-LEFT-DOWN" "tug_mark_mb";
    bind "ALT-LEFT-UP" "tug_drag_done_mb";
    bind "ALT-SHIFT-LEFT-DOWN" "tug_mark_mb";
    bind "ALT-SHIFT-LEFT-UP" "tug_drag_done_mb";
    bind "ALT-LEFT-DRAG" "tug_drag_mb";
    bind "ALT-SHIFT-LEFT-DRAG" "tug_drag_2_mb";

    unbind "SHIFT-LEFT-CLICK"
    bind "SHIFT-LEFT-CLICK" "_pickAtom";
    bind "SHIFT-LEFT-CLICK" "+:tug_anchor_mb";

    bind "ALT-CTRL-LEFT-CLICK" "_pickAtom";
    bind "ALT-CTRL-LEFT-CLICK" "+:tug_pivot_mb";

    bind "ALT-SHIFT-LEFT-CLICK" "_pickAtom";
    bind "ALT-SHIFT-LEFT-CLICK" "+:tug_dest_atom_mb";
}

# Bound to SHIFT-LEFT-CLICK by tug_cargo_mb
function tug_anchor_mb() {
    if ({atomIndex=_atomPicked}.chain == gChain) {
        var aPidx = get_sc_bb_idx( _atomPicked, gChain)

        var pno = {atomIndex=aPidx}.atomno
        if (pno > {atomIndex=gCcargoIdx}.atomno) {
            select {atomIndex=gCanchorIdx}
            halo off
            if (gCanchorIdx == aPidx) {
                gCanchorIdx = -1
                gCanchorNo = gMaxNo + 1
            }
            else {
                gCanchorIdx = aPidx
                gCanchorNo = {atomIndex=gCanchorIdx}.atomno
                select {atomIndex=gCanchorIdx}
                halo on
            }
            collect_bb_rotors(FALSE)
        }
        else if (pno < {atomIndex=gNcargoIdx}.atomno) {
            select {atomIndex=gNanchorIdx}
            halo off
            if (gNanchorIdx == aPidx) {
                gNanchorIdx = -1
                gNanchorNo = gMinNo - 1
            }
            else {
                gNanchorIdx = aPidx
                gNanchorNo = {atomIndex=gNanchorIdx}.atomno
                select {atomIndex=gNanchorIdx}
                halo on
            }
            collect_bb_rotors(TRUE)
        }
        else {
            tow_cargo_mb()
        }

        # Get moving atoms set
        gMovingSet = {((atomno < gCanchorNo) and (atomno > gNanchorNo)
            and (chain=gChain))}
    }
    select {gCargoSet}
}

# Bound to ALT-SHIFT-LEFT-CLICK by tug_cargo_mb
function tug_dest_atom_mb() {
    var aOk = TRUE
    if ({atomIndex=_atomPicked}.chain == gChain) {

        var pno = {atomIndex=_atomPicked}.atomno
        if ((pno <= {atomIndex=gCcargoIdx}.atomno) and (pno >= {atomIndex=gNcargoIdx}.atomno)) {
            aOk = FALSE
        }
    }
    if (aOk) {
        select {atomIndex=gDestAtomIdx}
        star off
        if (gDestAtomIdx == _atomPicked) {
            gDestAtomIdx = -1
        }
        else {
            gDestAtomIdx = _atomPicked
            select {atomIndex=gDestAtomIdx}
            star on
        }
        select {gCargoSet}
    }
}

# Bound to CTRL-LEFT-CLICK by tug_cargo_mb
function tug_pivot_mb() {
    if (g1pivotIdx == _atomPicked) {
        color {atomIndex=g1pivotIdx} @gScheme
        if (g2pivotIdx >= 0) {
            g1pivotIdx = g2pivotIdx
            g2pivotIdx = -1
            g2dynamicIdx = -1
        }
        else {
            g1pivotIdx = -1
            g1dynamicIdx = -1
        }
    }
    else if (g2pivotIdx == _atomPicked) {
        color {atomIndex=g2pivotIdx} @gScheme
        g2pivotIdx = -1
        g2dynamicIdx = -1
    }
    else if (g1pivotIdx >= 0) {
        if (g2pivotIdx >= 0) {
            color {atomIndex=g2pivotIdx} @gScheme
        }

        g2pivotIdx = _atomPicked
        g2dynamicIdx = -1
        color {atomIndex=g2pivotIdx} green
    }
    else {
        g1pivotIdx = _atomPicked
        g1dynamicIdx = -1
        color {atomIndex=g1pivotIdx} green
    }
    select {gCargoSet}
}

# Bound to SHIFT-LEFT-CLICK by plico_tug
function tow_cargo_mb() {
    gTow = TRUE
    gChain = {atomIndex=_atomPicked}.chain
    gMinNo = {chain=gChain}.atomno.min
    gMaxNo = {chain=gChain}.atomno.max
    gCcargoIdx = -1
    gNcargoIdx = -1
    gCanchorIdx = -1
    gCanchorNo = gMaxNo + 1
    gNanchorIdx = -1
    gNanchorNo = gMinNo - 1

    # Highlight cargo cluster
    select {chain=gChain}
    gCargoSet = {selected}
    gMovingSet = {selected}
    set_colors()

    # Enable dragging
    tug_enable_drag()
    select {gCargoSet}
    halo off
    var es = gEcho.replace("anchors","mark chain")
    echo @es
    unbind "SHIFT-LEFT-CLICK"
    bind "SHIFT-LEFT-CLICK" "_pickAtom";
    bind "SHIFT-LEFT-CLICK" "+:tow_cargo_mb";
}

# Bound to ALT-LEFT-CLICK by plico_tug or called by plicotoab.toabCargoMB
function tug_cargo_mb() {

    # If O or movable side chain atom picked
    if (({atomIndex=_atomPicked}.atomName = "O")
        or (is_moveable_sc( _atomPicked))) {
        if (gSCidx >= 0) {
            draw gSCcircle DELETE
        }
        if (gSCidx == _atomPicked) {
            gSCidx = -1
        }
        else {
            gSCidx = _atomPicked
            gSCpt = {atomIndex=gSCidx}.xyz
            draw gSCcircle CIRCLE {atomIndex=gSCidx} MESH NOFILL
        }
    }
    else {
        if ({atomIndex=_atomPicked}.chain != gChain) {
            if (gTow) {
                select {chain=gChain}
                color {selected} @gScheme
            }
            gChain = {atomIndex=_atomPicked}.chain
            select ({atomIndex=gCcargoIdx} or {atomIndex=gNcargoIdx}
                or {atomIndex=gCanchorIdx} or {atomIndex=gNanchorIdx})
            halo off
            gCcargoIdx = -1
            gNcargoIdx = -1
            gCanchorIdx = -1
            gNanchorIdx = -1
        }
        gTow = FALSE
        gMinNo = {chain=gChain}.atomno.min
        gMaxNo = {chain=gChain}.atomno.max
        if (gNanchorIdx < 0) {
            gNanchorNo = gMinNo - 1
        }
        if (gCanchorIdx < 0) {
            gCanchorNo = gMaxNo + 1
        }
        var aPidx = get_sc_bb_idx( _atomPicked, gChain)

        gSCidx = -1
        draw gSCcircle DELETE

        # If existing cWard cargo picked
        if (gCcargoIdx == aPidx) {

            # Clear the highlight
            select {atomIndex=gCcargoIdx}
            halo off

            # If nWard cargo exists, mark it as the cWard cargo
            if (gNcargoIdx != gCcargoIdx) {
                gCcargoIdx = get_cp_idx(gNcargoIdx)
                gCcargoNo = {atomIndex=gCcargoIdx}.atomno
            }
            else {
                gCcargoIdx = -1
                gNcargoIdx = -1
            }
        }
        else if (gNcargoIdx == aPidx) {
            select {atomIndex=gNcargoIdx}
            halo off
            gNcargoIdx = get_nm_idx(gCcargoIdx)
            gNcargoNo = {atomIndex=gNcargoIdx}.atomno
        }
        else if (gCcargoIdx >= 0) {

            var no = {atomIndex=aPidx}.atomno

            # If pick is nWard of it
            if (no < {atomIndex=gCcargoIdx}.atomno) {

                # If exists, clear its highlight
                if (gNcargoIdx != gCcargoIdx) {
                    select {atomIndex=gNcargoIdx}
                    halo off
                }

                # Set new nWard cargo and highlight it
                gNcargoIdx = get_nm_idx(aPidx)
                gNcargoNo = {atomIndex=gNcargoIdx}.atomno
            }

            # Else cWard
            else {

                # Clear its old highlight
                select {atomIndex=gCcargoIdx}
                if (gNcargoIdx != gCcargoIdx) {
                    halo off
                }

                # Set new cWard cargo and highlight
                gCcargoIdx = get_cp_idx(aPidx)
                gCcargoNo = {atomIndex=gCcargoIdx}.atomno
            }
        }

        # Else no cWard cargo
        else {

            # Set new cWard cargo and highlight
            gCcargoIdx = get_cp_idx(aPidx)
            gCcargoNo = {atomIndex=gCcargoIdx}.atomno
            gNcargoIdx = get_nm_idx(gCcargoIdx)
            gNcargoNo = {atomIndex=gNcargoIdx}.atomno

            # Set default cWard anchor at cWard N
            var iNo = gMaxNo
            for (; iNo > 0; iNo--) {
                if ({(atomno=iNo) and (chain=gChain)}.atomName == "N") {
                    break;
                }
            }
            gCanchorIdx = {(atomno=iNo) and (chain=gChain)}.atomIndex
            gCanchorNo = {atomIndex=gCanchorIdx}.atomno
        }

        # If any anchor now inside cargo cluster, kill it
        if ({atomIndex=gCanchorIdx}.atomno <= {atomIndex=gCcargoIdx}.atomno) {
            gCanchorIdx = -1
            gCanchorNo = gMaxNo + 1
        }
        if ({atomIndex=gNanchorIdx}.atomno >= {atomIndex=gNcargoIdx}.atomno) {
            gNanchorIdx = -1
            gNanchorNo = gMinNo - 1
        }

        # Highlight cargo cluster
        select_nward_idx(gCcargoIdx, gNcargoIdx)
        gCargoSet = {selected}
        set_colors()

        # Collect the rotor sets
        collect_rotors()

        # Get moving atoms set
        gMovingSet = {((atomno < gCanchorNo) and (atomno > gNanchorNo)
            and (chain=gChain))}
    }

    # Enable dragging
    if (gToab) {
        toabEnableDrag()
    }
    else {
        tug_enable_drag()
    }
    
    select {gCargoSet}
}

# Top level of Tug
function plico_tug() {

    # Load common functions if not already
    if (kCommon < 2) {
        script $SCRIPT_PATH$plicoCommon.spt
        if (kCommon < 2) {
            prompt ("A newer version of plicoCommon.SPT is required")
            quit
        }
    }
    
    gPlico = "TUG"
    plico_prelim()
    gBondPicking = bondPicking
    set bondPicking TRUE
    set PickCallback "jmolscript:tug_pick_cb"
            
    gEcho = ("_________TUG_________|ALT-CLICK=mark block|SHIFT-CLICK=mark chain" +
        "|CLICK bond=freeze|DOUBLE-CLICK=exit")
    echo @gEcho
    gCrotors = array()
    gNrotors = array()
    clear_atom_idxs()

    bind "ALT-LEFT-CLICK" "_pickAtom";
    bind "ALT-LEFT-CLICK" "+:tug_cargo_mb";
    bind "SHIFT-LEFT-CLICK" "_pickAtom";
    bind "SHIFT-LEFT-CLICK" "+:tow_cargo_mb";
    bind "DOUBLE" "tug_exit";
}

# Bound to DOUBLE by plico_tug
function tug_exit() {
    set bondPicking gBondPicking
    set PickCallback NONE
    plico_exit()
}

# End of TUG.SPT

Contributors

Remig