--[[-- Mandulia -- Mandelbrot/Julia explorer Copyright (C) 2010 Claude Heiland-Allen 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 . --]]-- 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