Skip to content

Instantly share code, notes, and snippets.

@pigeonhill
Last active May 10, 2020 20:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pigeonhill/2c799711e1a774b4ebe1ef09d2d95749 to your computer and use it in GitHub Desktop.
Save pigeonhill/2c799711e1a774b4ebe1ef09d2d95749 to your computer and use it in GitHub Desktop.
Tilter Scripr
--[[
Tilter
Release 0.86
May 2020
Copyleft: Garry George 2020
photography.grayheron.net
--]]
require("config")
change_key = KEY.MENU
trigger_time = dryos.ms_clock
trigger_delay = 2000
toggle_screen = false
last_key = 0
infinity = 655241 -- trap ML reported infinity
tilt_angle = 0
f = lens.focal_length
fov = 0
tanal = 0
cot = 0
max_mag = 0.34
min_x = 210 -- in mm
fovang = 0
lens_t = (max_mag*min_x - f*(1+max_mag)*(1+max_mag))/max_mag -- lens 'thickness' based on a split thin lens model
x = lens.focus_distance
a = camera.aperture.value
H = lens.hyperfocal - f -- referenced to the lens front principal plane
angu = 0
angl = 0
ang = 0
jx = 0
ux = 0
J = 0
J_in = 0
rad = 100
H_scale = 3
text1 = " "
text2 = " "
text3 = " "
text4 = " "
text5 = " "
image_taken = false -- that is at least one has been taken
choices0 = {"OFF","ON"}
choices1 = {"Landscape","Portrait","L:Fully Shifted","P:Fully Shifted"}
choices2 = {"Text Only","Small","Medium","Large"}
switched_off = false
turned_off = false
function u(xx) -- focus distance from front lens principal plane
local u = xx - lens_t - (1+max_mag*min_x/xx)*f
return u
end
function my_display(text,time,x_pos,y_pos)
text = string.rep("\n",y_pos)..string.rep(" ",x_pos)..text
display.notify_box(text,time*1000)
end
function myround(nu,dp)
-- nu = a number, dp = decimal places required to show
-- returns number as a string
if dp == 0 then
nu = tostring(math.floor(nu))
else
nu = tostring(math.floor(nu)).."."..string.sub(tostring(math.floor(nu*10^dp)),-dp,-1)
end
return nu
end
function update()
tilt_angle = menu.get("Tilter","Hinge Angle",1)/10
f = lens.focal_length -- added to allow f to vary when not using a TS-E prime (albeit with a fixed lens thickness)
H = u(lens.hyperfocal) -- Split thin lens estimate H from front principal plane
x = lens.focus_distance -- sensor to focus distance as reported by Canon/ML
ux = u(x) -- estimate of focus distance from front 'principal' plane: assuming a split thin lens model
a = camera.aperture.value
J = f/math.sin(math.rad(menu.get("Tilter","Hinge Angle",1)/10))
jx = J*ux/H -- depth of field at ux, parallel to the sensor, based on the DoF at H being J parallel to the sensor
ang = math.atan(J/ux) -- angle of plane of sharp focus
angu = math.atan((J+jx)/ux) -- angle of upper (or near) DoF
angl = math.atan((J-jx)/ux) -- angle of lower (or far) DoF
if menu.get("Tilter","Orientation"," ") == "Landscape" then
fovang = 24
elseif menu.get("Tilter","Orientation"," ") == "Portrait" then
fovang = 36
elseif menu.get("Tilter","Orientation"," ") == "L:Fully Shifted" then
fovang = 48
elseif menu.get("Tilter","Orientation"," ") == "P:Fully Shifted" then
fovang = 60
end
fov = math.atan(fovang/(2*f)) -- in radians
local len = FONT.MED:width(text1)
display.print(text1,720 - len, 40, FONT.MED,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
len = FONT.MED:width(text2)
display.print(text2,720 - len, 70, FONT.MED,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
len = FONT.MED:width(text3)
display.print(text3,720 - len, 100, FONT.MED,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
len = FONT.MED:width(text4)
display.print(text4,720 - len, 130, FONT.MED,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
len = FONT.MED:width(text5)
display.print(text5,720 - len, 160, FONT.MED,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
text1 = "(U):"..myround(math.deg(angu),0).."deg "
len = FONT.MED:width(text1)
display.print(text1,720 - len, 40, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
text2 = "(F):"..myround(math.deg(ang),0).."deg "
len = FONT.MED:width(text2)
display.print(text2,720 - len, 70, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
text3 = "(L):"..myround(math.deg(angl),0).."deg "
len = FONT.MED:width(text3)
display.print(text3,720 - len, 100, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
if J == infinity then text4 = "(J): @ Inf" else text4 = "(J):"..myround(J/10,0).."cm " end
len = FONT.MED:width(text4)
display.print(text4,720 - len, 130, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
text5 = "U-FoV:"..myround(math.deg(fov),0).."deg "
len = FONT.MED:width(text5)
display.print(text5,720 - len, 160, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
if menu.get("Tilter","Scale"," ") ~= "Text Only" then -- draw graphics
if menu.get("Tilter","Scale"," ") == "Small" then
rad = 100
elseif menu.get("Tilter","Scale"," ") == "Medium" then
rad = 150
else
rad = 200
end
display.circle(rad,240,3,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
display.circle(0,240,rad,COLOR.TRANSPARENT_BLACK,COLOR.TRANSPARENT_BLACK)
display.line(rad/H_scale,240-0.94*rad,rad/H_scale,240+math.sqrt((H_scale*H_scale - 1)/(H_scale*H_scale))*rad,COLOR.LIGHT_GRAY)
do -- display 15 degree tick marks
local var, limit, step = -75, 75, 15
while (var <= limit) do
local x1 = rad*math.cos(math.rad(var))
local y1 = 240-rad*math.sin(math.rad(var))
local x2 = (rad-10)*math.cos(math.rad(var))
local y2 = 240-(rad-10)*math.sin(math.rad(var))
display.line(x1,y1,x2,y2,COLOR.LIGHT_GRAY)
var = var + step
end
end
if tilt_angle ~=0 then
display.line(0,240,rad*math.cos(ang),240-rad*math.sin(ang),COLOR.YELLOW)
display.line(0,240,rad*math.cos(angu),240-rad*math.sin(angu),COLOR.YELLOW)
display.line(0,240,rad*math.cos(angl),240-rad*math.sin(angl),COLOR.YELLOW)
end
local minrad = 8
display.circle(0,240,minrad,COLOR.RED,COLOR.RED)
local temp = rad*J/(H*H_scale)
temp = math.sqrt(rad*rad - temp*temp)
display.circle(rad,240,5,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
display.line(10,240,rad,240,COLOR.WHITE)
display.line(rad*2/H_scale,240-5,rad*2/H_scale,240+5,COLOR.WHITE)
if J < H_scale*H then
local sJ = rad*J/(H*H_scale)
display.line(0,(240 - sJ),math.sqrt(rad*rad - sJ*sJ),(240 - sJ),COLOR.ORANGE)
display.rect(0, (240 - sJ)-4, 5, 8, COLOR.ORANGE, COLOR.ORANGE)
if fovang ~= 0 then
cot = ((2*f)/fovang)*((2*f)/fovang)
local y1 = (sJ*cot + math.sqrt(rad*rad*(1+cot) - sJ*sJ*cot))/(1+cot)
local x1 = math.sqrt(rad*rad - y1*y1)
display.line(0,(240 - sJ),x1,(240 - y1),COLOR.ORANGE)
y1 = (sJ*cot - math.sqrt(rad*rad*(1+cot) - sJ*sJ*cot))/(1+cot)
x1 = math.sqrt(rad*rad - y1*y1)
display.line(0,(240 - sJ),x1,(240 - y1),COLOR.ORANGE)
end
end
if x > H_scale*H then
display.circle(rad,240 ,5,COLOR.RED,COLOR.RED)
elseif x >= H and x <= H_scale*H then
display.circle(rad*ux/(H*H_scale),240,5,COLOR.GREEN1,COLOR.GREEN1)
else
display.circle(rad*ux/(H*H_scale),240,5,COLOR.YELLOW,COLOR.YELLOW)
end
display.circle(0,240,rad,COLOR.WHITE)
display.circle(0,240,rad+1,COLOR.WHITE)
if menu.get("Tilter","Ground Focus"," ") == "ON" then
local xf24 = 2*f*J/24
local xf36 = 2*f*J/36
local xf48 = 2*f*J/48
local xf60 = 2*f*J/60
if ux < xf60 then display.circle(10,340,5,COLOR.WHITE,COLOR.RED) else display.circle(10,340,5,COLOR.WHITE,COLOR.GREEN1) end
if ux < xf48 then display.circle(30,340,5,COLOR.WHITE,COLOR.RED) else display.circle(30,340,5,COLOR.WHITE,COLOR.GREEN1) end
if ux < xf36 then display.circle(50,340,5,COLOR.WHITE,COLOR.RED) else display.circle(50,340,5,COLOR.WHITE,COLOR.GREEN1) end
if ux < xf24 then display.circle(70,340,5,COLOR.WHITE,COLOR.RED) else display.circle(70,340,5,COLOR.WHITE,COLOR.GREEN1) end
end
end
end
function check_stuff()
if (lv.running and (not menu.visible)) and toggle_screen == true then
if menu.get("Overlay","Global Draw",0) == 0 then
menu.set("Overlay","Global Draw",1)
else
menu.set("Overlay","Global Draw",0)
end
toggle_screen = false
return
end
if (lv.overlays == 2 and not menu.visible) then
if (not switched_off) and (string.find(lens.name,"TS") ~= nil) then
display.draw(update)
turned_off = false
elseif (not turned_off) then
display.clear()
turned_off = true
end
end
end
Tilter_Menu = menu.new
{
parent = "Focus",
name = "Tilter",
help = "Helps with TS-E focusing and bracketing",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "ON or Off?",
help = "Switches the script on & off",
choices = choices0,
update = function(this)
if this.value == "ON" then
switched_off = false
turned_off = false
else
switched_off = true
turned_off = false
end
end,
},
{
name = "Hinge Angle",
help = "In 1/10 degrees increments",
min = 3,
max = 85,
value = 6,
rinfo = function(this)
tilt_angle = this.value/10
J = f/math.sin(math.rad(tilt_angle)) -- hinge height in mm
if J >= infinity then
J = infinity
return "J @ Inf"
else
J_in = myround(J/(25.5*12),1)
return myround(J/10,0).."cm".."/"..J_in.."ft"
end
end,
},
{
name = "Orientation",
help = "Used to show FoV",
choices = choices1,
},
{
name = "Ground Focus",
help = "Used to show if Focus > FoV = Green",
help2 = "left to Right:shifted-Port, shifted-Lan,Port, ",
choices = choices0,
},
{
name = "Scale",
help = "Used to adjust the display scale",
choices = choices2,
value = "Text Only",
},
}
}
if (x==0 or a==0 or f==0) then
my_display("Can't use script",2,0,0)
ok_2_go = false
menu.set("Focus","Tilter","OFF")
return
end
event.shoot_task = check_stuff
config.create_from_menu(Tilter_Menu) -- keep a track of the script's menu state at camera close
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment