Code
--[[
* Band Between Atoms -- Brow42
* Original Author: Brow42
* Version 1.0 Nov 7, 2017
* Bands between two atoms, even on the same or adjacent residue
* This works around restrictions in band.AddBetweenSegments by
* banding to a distant residue, then banding to an endpoint.
* 1.01 add error trap for builtin band, deletes helper band on addfail.
--]]
Helper = 1 -- This is a bandable residue that is not adjacent or equal to the target residue
HELPERFAIL=-1
ADDFAIL=-2
FAIL=0
-- Returns band id of new band, or zero or negative value on error. Uses Helper global variable
function AddBetweenSegments(res1, res2, atom1, atom2) -- atom arguments are optional
if math.abs(res2-res1) > 1 then
success,addedband = pcall(band.AddBetweenSegments(res1,res2,atom1,atom2))
if not success then
print("Error making interresidue band:",addedband)
return ADDFAIL
end
return addedband
end
success, helperband = pcall(band.AddBetweenSegments,Helper,res2,0,atom2)
if not success then print("Error making helper band:",helperband) return HELPERFAIL end
success, addedband = pcall(band.AddToBandEndpoint,res1,helperband,atom1)
if not success then
band.Delete(helperband)
print("Error making requested band:",addedband)
return ADDFAIL
end
band.Delete(helperband)
return band.GetCount()
end
-- End generalized AddBetweenSegments
-- Begin helper and menu routines for Band Between Atoms
title = "Band Between Atoms 1.01"
print(title)
options = { res1=0, res2=0, atom1=0, atom2=0, helper=1, str=1.0, goal=3.5 } -- default values
NSeg = structure.GetCount()
NOriginalBands = band.GetCount()
function DeleteAddedBands()
if NOriginalBands == 0 then band.DeleteAll() end
while band.GetCount() > NOriginalBands do
band.Delete(NOriginalBands+1)
end
end
-- Returns 0 if no bandable pair exists in the puzzle (unlikely)
-- Helper is not adjacent to either residue specified
function FindHelper(excluded1,excluded2)
for i = 1,structure.GetCount()-2 do
local skip = (excluded1 and math.abs(i-excluded1)<=1) or (excluded2 and math.abs(i-excluded2)<=1)
if not skip then
for j = i+2,structure.GetCount() do
-- I was going to do band to space but that's just extra work
success,bandid = pcall(band.AddBetweenSegments,i,j)
if success and bandid > 0 then band.Delete(bandid) return i end
end
end
end
return 0 -- fail
end
-- ================================== Begin New Dialog Library Functions
-- Add a wall of text from a table
function dialog.AddLabels(d,msg,nlabels) -- pass in # of existing autolabels
local nlabels = nlabels or #(d._Order or {}) -- default, valid if never delete dialog elements
if type(msg) == 'string' then
msg = { msg }
end
for i = 1,#msg do
d['autolabel'..tostring(i+nlabels)] = dialog.AddLabel(msg[i])
end
end
-- Create but don't display a wall of text and 1 or 2 buttons
function dialog.CreateMessageBox(msg,title,buttontext1,buttontext0,buttontext2)
title = title or ''
local d = dialog.CreateDialog(title)
dialog.AddLabels(d,msg)
buttontext1 = buttontext1 or 'Ok'
d.button = dialog.AddButton(buttontext1,1)
if buttontext2 ~= nil then d.button2 = dialog.AddButton(buttontext2,2) end
if buttontext0 ~= nil then d.button0 = dialog.AddButton(buttontext0,0) end
return d
end
-- Display a dialog box
function dialog.ShowMessageBox(msg,title,buttontext1,buttontext0,buttontext2)
return dialog.Show(dialog.CreateMessageBox(msg,title,buttontext1,buttontext0,buttontext2))
end
-- Display a box AND print to the output
function ErrorMessage(msg,title)
if type(msg) == 'string' then
msg = { msg }
end
for i = 1,#msg do
print(msg[i])
end
return dialog.ShowMessageBox(msg,title)
end
-- ======================================= End Dialog Functions
-- Begin main menu and main()
OKAY = 1
FINDHELPER = 2
DATAERROR = 3
FATAL = -1
CANCEL = 0 -- cancel is always 0
function OptionsDump()
for u,v in pairs(options) do
print(u,v)
end
end
function Validate()
if options.res1 < 1 or options.res2 < 1 or options.helper < 1 or options.res1 > NSeg or options.res2 > NSeg or options.helper > NSeg then
ErrorMessage({"Residue numbers must be between 1 and","the # of residues."},"Data Entry Error")
return false
end
if options.atom1 < 0 or options.atom2 < 0 then
ErrorMessage("Atom numbers must be 0 (default atom) or positive.","Data Entry Error")
return false
end
if options.goal <= 0.0 then
ErrorMessage("The goal length must be > 0.", "Data Entry Error")
return false
end
if options.res1 == options.res2 and options.atom1 == options.atom2 then
ErrorMessage("You seem to be banding an atom to itself!")
return false
end
return true
end
function MainMenu()
local d = dialog.CreateDialog(title)
d["label1"] = dialog.AddLabel("This script adds a band between any two atoms on")
d["label2"] = dialog.AddLabel("any two residues. It works even if banding between")
d["label3"] = dialog.AddLabel("two atoms on the same residue, or adjacent residues,")
d["label4"] = dialog.AddLabel("but this requires an extra helper residue. Click the")
d["label5"] = dialog.AddLabel("Helper button to find a helper that works.")
d["label6"] = dialog.AddLabel("")
d["label7"] = dialog.AddLabel("Atom 0 is a default atom, but you should avoid")
d["label8"] = dialog.AddLabel("using it on a single residue to avoid banding")
d["label9"] = dialog.AddLabel("an atom to itself!")
d["label10"] = dialog.AddLabel("")
d["res1"] = dialog.AddTextbox("Residue 1:",tostring(options.res1))
d["res2"] = dialog.AddTextbox("Residue 2:",tostring(options.res2))
d["atom1"] = dialog.AddTextbox("Atom 1:",tostring(options.atom1))
d["atom2"] = dialog.AddTextbox("Atom 2:",tostring(options.atom2))
d["helper"] = dialog.AddTextbox("Helper residue:",tostring(options.helper))
d["str"] = dialog.AddSlider("Strength:",tostring(options.str),0.1,10,1)
d["goal"] = dialog.AddTextbox("Goal Length:",tostring(options.goal))
d["ok"] = dialog.AddButton("OK",OKAY)
d["find"] = dialog.AddButton("Helper",FINDHELPER)
d["cancel"] = dialog.AddButton("Cancel",CANCEL)
local rc = dialog.Show(d)
if rc == CANCEL then return CANCEL end
local conv,convfail = nil,false
for u,v in pairs(options) do
conv = tonumber(d[u].value)
if conv then options[u] = conv
else convfail = true end
end
if convfail == true then
ErrorMessage("Numerical values only please!","Data Entry Error")
return DATAERROR
end
if Validate() == false then return DATAERROR end
NeedHelper = math.abs(options.res2-options.res1) <= 1
if rc == FINDHELPER then
options.helper = FindHelper(options.res1,options.res2)
if options.helper == 0 then
ErrorMessage({"Couldn't find a second bandable residue.","You might not be able to use this script on this puzzle."},"No Helper Found!")
return FATAL
else
ErrorMessage("New helper picked!","Helper Residue")
print("New helper residue is",options.helper)
end
else if NeedHelper and math.abs(options.res2 - options.helper) <= 1 then
ErrorMessage({"Helper is too close to Residue 2. Swap Residue 1","and Residue 2 or pick a new helper."},"Helper Residue")
return DATAERROR
end
end
return rc
end
-- ========================= Begin Main
repeat
rc = MainMenu()
if rc == CANCEL then print("User cancel.") end
if rc == CANCEL or rc == FATAL then return end
until rc == OKAY
Helper = options.helper
NewBand = AddBetweenSegments(options.res1,options.res2,options.atom1,options.atom2)
if NewBand == HELPERFAIL then
ErrorMessage({"Couldn't band between the helper residue and the target.",
"Check the error message in the output window and","message the script author.",
"(perhaps atom number too high?)"},title)
OptionsDump()
return
end
if NewBand == ADDFAIL then
ErrorMessage({"Couldn't make the desired band",
"Check the error message in the output window and","message the script author.",
"(perhaps atom number to high?)"},title)
OptionsDump()
return
end
if NewBand == 0 then
ErrorMessage({"Something went wrong, the band couldn't be made."},title)
OptionsDump()
return
end
band.SetStrength(NewBand,options.str)
band.SetGoalLength(NewBand,options.goal)
print(string.format("New band #%d\nCreated from res %d, atom %d to res %d, atom %d,",
NewBand,options.res1,options.atom1,options.res2,options.atom2))
print(string.format("with strength %.2f, goal length %.2f, and current length %.2f",
options.str,options.goal,band.GetLength(NewBand)))
if band.GetLength(NewBand) == 0.0 then
ErrorMessage("You've made a zero length band! I'm deleting it.","Warning: Black Hole Ahead")
band.Delete(NewBand)
end
print "Done."