An orbital speeds script
Posted: 05.05.2004, 20:54
Hello,
this script puts the viewer above the selected body and computes tangential, angular and radial speeds for it, with respect to its "parent" body (e.g. Earth-Sol, ISS-Earth, Dactyl-Ida, etc.)
LUA precision limitations arise at high time speeds, or when viewer is really close to small bodies
EDIT: I have modified the way speeds are computed (see below)
Please post bugs, suggestions and comments here.
Bye
this script puts the viewer above the selected body and computes tangential, angular and radial speeds for it, with respect to its "parent" body (e.g. Earth-Sol, ISS-Earth, Dactyl-Ida, etc.)
LUA precision limitations arise at high time speeds, or when viewer is really close to small bodies
Code: Select all
--*********************************************************************
--*********************************************************************
-- A script for computing speeds
-- coded by Toti
--*********************************************************************
--*********************************************************************
--*********************************************************************
-- constants
--*********************************************************************
DELAY = 0.5
HORIG = 0
VORIG = -1
KM_MLY = 9466411.842
SEC_DAY = 86400
ANGLE = 20
TAN_ANGLE = math.tan(math.rad(ANGLE)) -- this one is used by viewBodyAbove(), but it's done here because of
-- performance
HOW_FAR = 1.1 -- this one is used by viewBodyAbove(), it's a measure of how close
-- the viewer is from parent body
DELTA_S = 1000 -- time increment in seconds (default: 100 sec. = 16.6 min. you can reduce
-- this in order to get smaller "differentials")
DELTA_D = DELTA_S / SEC_DAY -- time increment converted to days (default: about 0.011 days)
obs = celestia:getobserver()
--*********************************************************************
-- flags and status save and restoration functions
--*********************************************************************
function setRenderOn ()
-- sets the necessary renderflags on
celestia:setrenderflags{constellations=false,eclipseshadows=true,galaxies=true,grid=false,lightdelay=false,markers=true,
nightmaps=true,orbits=true,planets=true,ringshadows=true,smoothlines=false,stars=true}
end
function setRenderOff ()
-- sets the necessary renderflags off
celestia:setrenderflags{markers=false,orbits=false}
-- a 'labels' render flag would be handy:
celestia:setlabelflags{asteroids=false,comets=false,moons=false,planets=false,spacecraft=false,constellations=false,
galaxies=false,locations=false,stars=false}
end
function setOrbits (sType)
-- sets the orbit on for this particular body's type. (There is probably a direct way to do this):
local t = {}
t.Asteroid = false
t.Comet = false
t.Moon = false
t.Planet = false
t.Spacecraft= false
if sType == "asteroid" then
t.Asteroid = true
elseif sType == "comet" then
t.Comet = true
elseif sType == "moon" then
t.Moon = true
elseif sType == "planet" then
t.Planet = true
elseif sType == "spacecraft" then
t.Spacecraft= true
end
celestia:setorbitflags(t)
end
function setLabels (sType)
-- sets the label on for this particular body's type. (Again, there is probably a direct way to do this):
local t = {}
t.asteroids = false
t.comets = false
t.moons = false
t.planets = false
t.spacecraft = false
t.constellations = false
t.galaxies = false
t.locations = false
t.stars = false
if sType == "asteroid" then
t.asteroids = true
elseif sType == "comet" then
t.comets = true
elseif sType == "moon" then
t.moons = true
elseif sType == "planet" then
t.planets = true
elseif sType == "spacecraft" then
t.spacecraft = true
t.planets = true
end
celestia:setlabelflags(t)
end
function celestia_cleanup_callback()
-- restore user's settings
celestia:setrenderflags(oldrf)
celestia:setlabelflags(oldlf)
celestia:setorbitflags(oldof)
end
function saveOldSettings()
--store user's settings
oldrf = celestia:getrenderflags()
oldlf = celestia:getlabelflags()
oldof = celestia:getorbitflags()
end
--*********************************************************************
-- some support functions
--*********************************************************************
function selectpair()
local s = celestia:getselection()
local p
if s:type() == "null" then -- nothing selected
s = nil
else
if s:type() == "star" then -- stars does not have parent, so select its first son
p = s
s = p:getchildren()[1]
if s ~= nil then -- this star does not have orbiting bodies
celestia:select(s)
end
else -- the son is another class of body
p = s:getinfo()['parent']
end
end
if s ~= nil then
setRenderOn()
setOrbits(s:type())
setLabels(s:type())
celestia:unmarkall()
s:mark ("#ff0000", "diamond", 30)
p:mark ("#ffff00", "diamond", 50)
else
setRenderOff()
end
return s, p
end
function viewBodyAbove (norm, sPos, pPos)
-- puts the observer perpendicular to the local orbit's plane, "above" the parent.
-- because our line of sight will be locally orthogonal to the orbital plane, we can use simple trigonometrics to
-- calculate the distance we need to be placed from parent, in order to see both son and parent with an angle = ANGLE
local radiusVector = sPos-pPos
local distance = radiusVector:length() * HOW_FAR / TAN_ANGLE
-- place the viewer
obs:setposition ( pPos + (norm * distance) )
-- keep the top of the screen oriented along radiusvector
obs:lookat (pPos, radiusVector)
end
--*********************************************************************
-- speed functions
--*********************************************************************
function tspeed (p0, p1, dt)
-- tangential speed
return (p1-p0):length() * KM_MLY / dt
end
function aspeed (p0, p1, dt)
-- angular speed
return math.deg( math.acos( (p0*p1)/( p0:length() * p1:length() ) ) ) / dt
end
function rspeed (p0, p1, dt)
-- radial speed
return (p1:length() - p0:length()) * KM_MLY / dt
end
--*********************************************************************
-- main script
--*********************************************************************
--save Celestia status
saveOldSettings()
repeat
son, par = selectpair()
if son ~= nil then
parPos = par:getposition()
sonPos = son:getposition()
sonPosR1 = parPos - sonPos
t1 = celestia:gettime()
t0 = t1 - DELTA_D
sonPosR0 = par:getposition(t0) - son:getposition(t0) -- parent is moving
ts = tspeed (sonPosR0, sonPosR1, DELTA_S)
as = aspeed (sonPosR0, sonPosR1, DELTA_S)
rs = rspeed (sonPosR0, sonPosR1, DELTA_S)
celestia:print(string.format("Speeds relative to " .. par:name() .. "\nTangential: %4.5f km/sec\nAngular: %14.15f deg/sec\nRadial: %4.5f km/sec", ts, as, rs), DELAY, HORIG, VORIG)
-- compute a normal for the orbit. It must be done inside the loop because of local planar accuracy
normal = (sonPosR0^sonPosR1):normalize()
-- if you want to move freely, just comment this line
viewBodyAbove (normal, sonPos, parPos)
end
wait()
until 1==2
EDIT: I have modified the way speeds are computed (see below)
Please post bugs, suggestions and comments here.
Bye