Skip to content

Instantly share code, notes, and snippets.

@pigeonhill pigeonhill/TILT.LUA
Last active Nov 12, 2019

Embed
What would you like to do?
Tilter Scripr
--[[
Tilter
Release 0.71
Nov 2019
Copyleft: Garry George 2019
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
last_angu = 0
last_angl = 0
last_ang = 0
jx = 0
ux = 0
J = 0
rad = 200
H_scale = 3
text1 = " "
text2 = " "
text3 = " "
text4 = " "
text5 = " "
text6 = " "
text7 = " "
card_count = dryos.shooting_card.file_number
image_taken = false -- that is at least one has been taken
inf_blur = 0
diff_blur = 0
tot_blur = 0
freq = 0.550 -- 0.550 for visible band photography or 0.850 for IR (or another frequency to suit your sensor conversion)
CON = "ON"
COFF = "OFF"
choices0 = {COFF,CON}
choices1 = {"Off","Landscape","Portrait","L:Fully Shifted","P:Fully Shifted"}
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()
if card_count ~= dryos.shooting_card.file_number then
last_ang = ang
last_angu = angu
last_angl = angl
card_count = dryos.shooting_card.file_number
image_taken = true
end
f = lens.focal_length -- added to allow f to vary when not using a TS-E prime (albeit with a fixed lens thickness)
H = lens.hyperfocal - f -- 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
inf_blur = menu.get("DOF Settings","Circle of Confusion",0) -- script assumes that the ML blur is the optical (CoC) blur criterion
diff_blur = 2.44 * a * freq
tot_blur = math.sqrt(inf_blur*inf_blur + diff_blur*diff_blur)
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
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
if image_taken and (angl <= last_angu and angu >= last_angu) then
display.circle(0,240,minrad,COLOR.GREEN1,COLOR.GREEN1)
elseif image_taken and (angu >= last_angl and angl <= last_angl) then
display.circle(0,240,minrad,COLOR.GREEN1,COLOR.GREEN1)
else
display.circle(0,240,minrad,COLOR.RED,COLOR.RED)
end
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)
fovang = 0
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
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)
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)
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
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)
len = FONT.MED:width(text6)
display.print(text6,720 - len, 190, FONT.MED,COLOR.TRANSPARENT,COLOR.TRANSPARENT)
len = FONT.MED:width(text7)
display.print(text7,720 - len, 220, 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 = "(O/D/T):"..myround(inf_blur,0).."/"..myround(diff_blur,0).."/"..myround(tot_blur,0).."um "
len = FONT.MED:width(text5)
display.print(text5,720 - len, 160, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
text6 = "U-FoV:"..myround(math.deg(fov),0).."deg "
len = FONT.MED:width(text6)
display.print(text6,720 - len, 190, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
text7 = "#B2G:"..myround(math.ceil(H/(2*ux)+0.5),0).." "
len = FONT.MED:width(text7)
display.print(text7,720 - len, 220, FONT.MED, COLOR.WHITE,COLOR.TRANSPARENT_BLACK)
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
display.circle(0,240,rad,COLOR.WHITE)
display.circle(0,240,rad+1,COLOR.WHITE)
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) then
display.draw(update)
turned_off = false
elseif (not turned_off) then
display.clear()
turned_off = true
end
end
end
function screen_update_check(kk)
if kk == change_key then
if last_key == change_key then
if dryos.ms_clock - trigger_time > trigger_delay then
toggle_screen = true
last_key = 0
return false
else
last_key = 0
toggle_screen = false
return true
end
else
trigger_time = dryos.ms_clock
last_key = key.last
toggle_screen = false
return false
end
return true
else
return true
end
return true
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,
update = function(this)
tilt_angle = this.value/10
J = f/math.sin(math.rad(tilt_angle)) -- hinge height in mm
end,
rinfo = function(this)
if J >= infinity then
J = infinity
return "J @ Inf"
else
return myround(J/10,0).."cm"
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,
},
}
}
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
event.keypress = screen_update_check
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
You can’t perform that action at this time.