mandulia-0.4: config/transition.lua
--[[--
Mandulia -- Mandelbrot/Julia explorer
Copyright (C) 2010 Claude Heiland-Allen <claudiusmaximus@goto10.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]--
do
--[[--
SYNOPSIS
s, f = transition(a, b, p, q)
INPUTS
a ~ {x,y,z} z >= 0 : source viewpoint coordinates
b ~ {x,y,z} z >= 0 : target viewpoint coordinates
p > 0 : zoom vs move weighting (smaller => zoomier)
q > 1 : zoom factor
OUTPUTS
s >= 0 : source->target path length
f(t) ~ {x,y,z} z >= 0 : viewpoint interpolator
where 0 <= t <= s
EXAMPLE
s, f = transition(a, b, p, q)
for t = 0,s,dt do
view = f(t)
end
--]]--
function transition(aa, bb, pp, qq)
-- copy arguments
local a = { x = aa.x, y = aa.y, z = aa.z }
local b = { x = bb.x, y = bb.y, z = bb.z }
local p = pp
local q = qq
-- transform coordinates
local logp = math.log(p)
local logq = math.log(q)
local function y(z) return p * (q ^ (-z)) end
local function z(y)
if y > 0 then
return math.max((logp - math.log(y)) / logq, 0)
else
return 0
end
end
-- initial coordinates
local dx = b.x - a.x
local dy = b.y - a.y
-- local x0 = 0
local y0 = y(a.z)
local x1 = math.sqrt(dx * dx + dy * dy)
local y1 = y(b.z)
if x1 > 0 then -- circular arc centered on x-axis
local xc = (x1*x1 + y1*y1 - y0*y0) / (2 * x1)
local a0 = math.atan2(y0, - xc)
local a1 = math.atan2(y1, x1 - xc)
local r = math.sqrt(xc*xc + y0*y0)
local s = r * math.abs(a1 - a0)
local da = (a1 - a0) / s
local fx = dx / x1
local fy = dy / x1
return s, function(t)
local at = a0 + t * da
local dr = xc + r * math.cos(at)
return { x = a.x + fx * dr
, y = a.y + fy * dr
, z = z(r * math.sin(at))
}
end
else
local s = math.abs(y1 - y0)
if s > 0 then -- vertical line segment
local ds = (y1 - y0) / s
return s, function(t)
return { x = a.x, y = a.y, z = z(y0 + t * ds) }
end
else -- end points are identical
return 0, function(t)
return { x = a.x, y = a.y, z = a.z }
end
end
end
end
end