Page 1 of 1

goto always to sunny face of planet

Posted: 16.06.2009, 16:11
by loberlat
Hello,
I have to write a script to show to children, the planets of our solar system.
First, I begin to place my observer at a zenital position of the sun and show the orbit of planets.
Second, I have to go to a planete, to its sunny side, ans accelerate time to make it one complete turn in 10 seconds.
and after, I return to my initial position, a zenital position of the sun.

My problem is that I can't place my obs near the selected planet with the sun in observer's back. I want to use the goto command but I don't know how to calculate the position point and the rotation of my observer. It's very hard for me to move in a 3D world... I worked to this problem for 3 days with no result... argh.....

Can someone illuminate me?

Thank a lot...

Re: goto always to sunny face of planet

Posted: 18.06.2009, 20:20
by cpotting
The below code is for a function I created some time ago called travel_to. It is definitely over-powered for what you want to do, but it will position your observer as you indicated with only a few parameter settings. Unfortunately, I am pressed for time at the moment and can't take the time to write out a smaller code snippet.

Once you include the function you will be able to position the observer to view the sunlit portion of Mars as follows:

Code: Select all

MARS  = celestia:find("Sol/Mars")
travel_to{ body=MARS, location="over subsolar point"}


Look at the comments in the function for how to adjust the distance from the planet (e.g. try changing location to
  • "above subsolar point"
  • "viewing subsolar point"
  • ".5AU above subsolar point"
  • "2RADII above subsolar point"
  • "5000KM above subsolar point"
You could also play with the duration parameter to speed up/slow down the trip:

Code: Select all

travel_to{ body=MARS, location="over subsolar point", duration=20}

You may also want to make sure you are facing Mars:

Code: Select all

travel_to{ body=MARS, location="over subsolar point", duration=20, tracking=MARS}
or

Code: Select all

travel_to{ body=MARS, location="over subsolar point", duration=20, final_tracking=MARS}


The code for the function is:

Code: Select all

--[[ Move observer to a given position using the parameters supplied as the table travel_parms.  Items in travel_parms
     are:
      adjust_time - Determines if travel_to() will use a shorter duration when the start and ending positions are close
                    to each other.
                      e.g. travel_to({ body=EARTH, duration=60, tracking=EARTH });wait(10)
                           travel_to({ body=EARTH, duration=60, tracking=EARTH });wait(10)
                           travel_to({ body=EARTH, duration=60, tracking=EARTH, adjust_time=false });wait(10)
                      the second travel_to() only has to go a few km and will use a shorter value for duration.
                      the third travel_to() also has to go a few km, but will take a full 60 seconds to do so.
                      default: true
      at          - The time (specified in julian days) that the simulation should be set to when the trip completes.
                     default: the (current time + duration) * current timescale
      body          - String or object indicating the body that placement will be relative to.
                       default: the point indicated by the universal coordinates 0, 0, 0.
      calc_only   - If present and set to true, then travel_to does not move the observer.  Instead the location that
                    the observer would be moved to is calculated and returned as a position.
                     default: false.
        location    - Text description of where the observer will be placed.  May contain any of the following locales:
                     "covisual"    - A position 10 degrees from the subcynthion antipodal point and 9 radii from the
                                     body, from which it is possible to view both the body and the reference_body
                                     (within a standard field of view of approximately 24 degrees).
                     "pole"        - The approximate north pole of the body.  Note: a known bug in Celestia causes this
                                     point to be calculated as vertical to the ecliptic, not the equator.  This means
                                     that "pole" points to a point on the body's "arctic circle".
                     "subcynthion" - The point on the surface of the body where the reference_body will appear at
                                     zenith.  "subcynthion" is my own term derived from "subpolar point" (the point on
                                     Earth directly under the Sun) and "pericynthion" (the closest point in an object's
                                     orbit around an artificial body [the closest term I could find])
                     "subsolar"    - Same as "subcynthion".  Provided for convienience since the most common usage of
                                     "subcynthion" will be a reference to the "subsolar point".
                         "terminator"  - A position 89 degrees from the line between the body and the reference_body. 
                                     Since the default location_reference will usually be a star (the Sun), this will
                                     usually place the observer over the day-night terminator.
                     "longlat x,y" - A position at longitude x, latitude y on the surface of the body.  Note: x any y
                                     are given in degrees, may be negative and may include decimals.  x and y must be
                                     seperated only by a comma - no spaces are allowed.
                    and any combination of the following modifiers:
                     "above"     - The observer will be placed 1.1 radii from the body.
                     "antipodal" - Rotates the vector from the body to the observer by 180 degrees.
                     "antipous"  - The same as "antipodal" ("anitpous" is the singular of "antipodes").
                     "diagonal"  - Rotates the vector from the body to the observer by 45 degrees.
                     "from"      - Ignored.  Provided to allow expressions such as "viewing terminator from 5AU".
                       "left"      - Indicates that rotation of the vector from the body to the observer should be
                                   "left-handed" (or clockwise as seen from 'above') (e.g. "over left terminator"
                                   places the observer over the object's leading terminator (for prograde orbits).
                       "over"      - The observer will be placed 6 radii from the body.
                     "point"     - Ignored.  Provided to allow expressions such as "over subsolar point" and
                                   "diagonal to subcynthion point".
                       "right"     - Indicates that rotation of the vector from the body to the observer should be
                                   "right-handed" (or counter-clockwise as seen from 'above') (c.f. "left").
                     "to"        - Ignored.  Provided to allow expressions such as "diagonal to terminator".
                     "viewing"   - The observer's distance from the body will be 98% of the distance to the
                                   reference_body.
                                   Note: "over" and "above" are ignored if "viewing" is used.
                     "xAU"       - Where x is an number, the observer will be placed x astronomical units from body.
                     "xKM"       - Where x is an number, the observer will be placed x kilometres from body.
                     "xRADII"    - Where x is an number, the observer will be placed x times the radius of the body
                                   from body.
                    Note: "over", "above" and "viewing" become ignored words if "xAU", "xKM" or "xRADII" are used.
                    Defaults are "subsolar", "right" and "over".
        reference_body -
                    - a second body which is used in calculating some locations (i.e. "terminator", "subcynthion").
                       default: the primary of the system to which body belongs, or Sol if body is nil
      position    - a position (in universal coordinates) to which the observer will be moved.
                    Note: if position is specified, then body, location, and reference_body cannot be used.
        observer      - indicates which observer should travel.
                       default: the current observer.
        duration      - the number of seconds this trip will take.
                       default: 10.
      initial_tracking
                  - a body to be centred and remain centred on the screen at the start of the trip.  Note that up to
                    1/10 of the trip time or 3 seconds (whichever is less) may be devoted to turning the observer
                    towards the body before the actual movement begins.  The body will remain centred until the
                    time specified by start_interpolation is reached.
                    initial_tracking cannot be used with tracking or initial_orientation.
                     default: no tracking.  The observer remains in its initial orientation until the
                              start_interpolation time is reached.
      final_tracking
                  - a body to be centred and remain centred on the screen during the latter portion of the trip.  The
                    observer will begin turning toward the body once the start_interpolation time is reached and be
                    fully turned when the end_interpolation time is reached.
                    final_tracking cannot be used with tracking or final_orientation
                     default: no tracking.  The observer remains in the same orientation it was in at the
                              start_interpolation time.
      tracking      - a body to be used as both the initial_tracking body and the final_tracking body.
                    tracking cannot be used with initial_tracking, initial_orientation, final_tracking or
                    final_orientation.
                    start_interpolation and end_interpolation are ignored when tracking is specified.
      final_up    - a vector indicating which direction will be "up" (towards the top of the screen) when then journey
                    is complete.  final_up cannot be used if final_orientation is given.
                     default: "up" for the initial_orientation
      initial_orientation
                  - the orientation the observer should have at the start of the trip.  Note that up to 1/10 of the trip
                    time or 3 seconds (whichever is less) may be devoted to truning the observer this orientation.  This
                    orientation will be maintained until the time specified by start_interpolation is reached.
                    initial_orientation cannot be used with tracking or initial_tracking.
                     default: the current orientation for the observer.
      final_orientation
                  - the orientation the observer should have at the end of the trip.  The observer will begin turning
                    toward the final_orientation once the start_interpolation time is reached and be fully turned when
                    the end_interpolation time is reached.
                    final_orientation cannot be used with tracking, final_tracking or final_up
                     default: no orientation change.  The observer remains in the same orientation it was in at the
                              start_interpolation time.
      start_interpolation
                  - the point in the trip (expressed as a percent) at which the observer should begin turning from the
                    the initial_orientation or intial_tracking body to the final_orientation or final_tracking body.
                     default: 0.25
      end_interpolation
                  - the point in the trip (expressed as a percent) at which the observer should finish turning from the
                    initial_orienation or intial_tracking body and now fully face the final_orientation or
                    final_tracking body.
                     default: 0.75
      accelTime   - indicates (as a percentage) how much of the trip should be spent accelerating away from the initial
                    location.  Also represents the amount of time that will be spent decelerating towards the final
                    location.  The remainder of the trip is spend cruising.
                     default: 0.25.  minimum: 0.01  maximum 0.5
      jerk         - indicates whether acceleration and deceleration should be at constant value (jerk=false) or at
                    an accelerating amount (jerk=true).  Jerk is the term for the rate of change of acceleration.
                     default: true
   The following constants may also be defined before calling travel_to():
      TRAVEL_TO_DURATION: when specified, this becomes the default value for travel_parms.duration.
      TRAVEL_TO_JERK:     when specified, this becomes the default value for travel_parms.jerk
     Note: control is not returned until the trip is complete, so wait() is not necessary with travel_to() ]]
function travel_to(travel_parms)
   -- obs = which of the open observers is to be moved
   local obs = travel_parms.observer
   if obs == nil then
      obs = celestia:getobserver()
   elseif not(obs:isvalid()) then
      obs = celestia:getobserver()
   end
   
   -- travel_time = seconds spent moving from start position to end position
   local travel_time = travel_parms.duration
   if travel_time == nil then
      travel_time = TRAVEL_TIME_DURATION
      if travel_time == nil then
         travel_time = 10
      end
   end
   
   -- endtime = simulation time once the journey is complete
   local endtime = travel_parms.at
   if endtime == nil then
      endtime = obs:gettime() + travel_time * celestia:gettimescale() /  SEC_PER_JDAY
   end
   
   -- initial_tracking = which object is to be tracked at the start of the journey
   -- final_tracking   = which object is to be tracked at the end of the journey
   -- start_interpolation = when to start switching from intial_tracking/_orientation to final_tracking/_orientation
   -- end_interpolation   = when to complete switching from intial_tracking/_orientation to final_tracking/_orientation
   -- centre_time = time devoted to reorienting the observer to the proper initial orientation
   local initial_tracking       = nil
   local initial_orientation    = nil
   local final_tracking       = nil
   local final_orientation    = nil
   local start_interpolation    = .25
   local end_interpolation      = .75
   local centre_time          = 0
   local vpixels_per_sec = 200 -- max turn rate while reorienting
   local radians_per_sec = 1   -- max roll rate while reorienting
   local final_up = travel_parms.final_up
   if final_up ~= nil and travel_parms.final_orientation ~= nil then
      celestia:flash("Illegial combination of parameters: final_up may not be used with final_orientation", 60);wait(60)
      error(1)
   end
   if travel_parms.tracking == nil then
      initial_tracking = travel_parms.initial_tracking
      if initial_tracking == nil then
         initial_orientation = travel_parms.initial_orientation
      elseif travel_parms.initial_orientation ~= nil then
         celesita:flash("Illegial combination of parameters: initial_orientation may not be used with initial_tracking",
                        60);wait(60);error(1)
      end
      final_tracking = travel_parms.final_tracking
      if final_tracking == nil then
         final_orientation = travel_parms.final_orientation
      elseif travel_parms.final_orientation ~= nil then
         celesita:flash("Illegial combination of parameters: final_orientation may not be used with final_tracking",
                        60);wait(60);error(1)
      end
   else
      -- tracking means we are to track one object through the entire journey
      if travel_parms.initial_tracking ~= nil or travel_parms.final_tracking ~= nil then
         celestia:flash("Illegial combination of parameters: initial_/final_tracking may not be used with tracking", 60)
         wait(60);error(1)
      elseif travel_parms.start_interpolation ~= nil or travel_parms.end_interpolation ~= nil then
         celestia:flash("Illegial combination of parameters: start_/end_interpolation may not be used with tracking",
                        60);wait(60);error(1)
      elseif travel_parms.initial_orientation ~= nil or travel_parms.final_orientation ~= nil then
         celestia:flash("Illegial combination of parameters: initial_/final_orientation may not be used with tracking",
                        60);wait(60);error(1)
      end
      -- set the tracking object as both the intial_tracking and final_tracking objects
      initial_tracking = travel_parms.tracking
      final_tracking   = travel_parms.tracking
      -- since we are tracking a single object, if there is no final_up parameter then there is no need for an
      -- interpolation phase
      if final_up == nil then
         start_interpolation = 0
         end_interpolation = 0
      end
   end
   
   -- goto_position = destination is a specific set of coordinates in space in the universal frame of reference
   local goto_position = travel_parms.position
   if goto_position == nil then
      goto_position = celestia:newposition(0, 0, 0)
   elseif travel_parms.body ~= nil then
      celestia:flash("Illegial combination of parameters: body may not be used with position", 60);wait(60);error(1)
   elseif travel_parms.location ~= nil then
      celestia:flash("Illegial combination of parameters: location may not be used with position", 60);wait(60);
      error(2)
   elseif travel_parms.reference_body ~= nil then
      celestia:flash("Illegial combination of parameters: reference_body may not be used with position", 60);
      wait(60);error(3)
   end
   
   -- body = destination will be a point located relative to the given body
   -- body_radius = size of the body
   -- body_up = direction from the body's centre to its north pole
   local body = travel_parms.body
   if type(body) == "string" then
      body = celestia:find(body)
   end
   local body_radius, body_up
   if body == nil then
      body_radius = 0
      body_up     = celestia:newvector(0, 1, 0)
   else
      goto_position = body:getposition(endtime)
      body_radius   = body:radius()
      body_up       = celestia:newframe("equatorial", body):from(celestia:newposition(.001, 1, 0), endtime) -
                      goto_position
   end
   
   -- reference_position = coorinates of a second body sometimes needed to specify the desired destination
   local reference = travel_parms.reference_body
   local reference_position
   if type(reference) == "string" then
      reference = celestia:find(reference)
   elseif reference == nil then
      if body == nil then
         reference = celestia:find("Sol")
      else
         reference = find_system_parent(body)
         if body == reference then
            reference = nil
         end
      end
   end
   if reference == nil then
      reference_position = celestia:newposition(0, 0, 0)
   else
      reference_position = reference:getposition(endtime)
   end
   
   -- parse the locale and modifiers
   local action = ""
   local angle = 0
   local angle_factor = 1
   local distance_factor = 6
   local viewing = false
   local viewing_AU = goto_position:distanceto(reference_position) * .98 / KM_PER_AU
   local ignore_tokens = { from=0, over=0, point=0, right=0, subcynthion=0, subsolar=0, to=0 }
   local token, token_value
   local token_is_longlat = false
   if travel_parms.location ~= nil then
      for token in string.gfind(travel_parms.location, "([%w%.,%-]+)%s*") do
         token = string.lower(token)
         token_value = tonumber(string.sub(token, 1, -3))
         if token_is_longlat then
            for long, lat in string.gfind(token, "([%d%.%-]+),([%d%.%-]+)") do
               local distance = reference_position:distanceto(goto_position)
               local x = - distance * math.cos(math.rad(long)) * math.cos(math.rad(lat))
               local y = distance * math.sin(math.rad(lat))
               local z = distance * math.sin(math.rad(long)) * math.cos(math.rad(lat))
               reference_position =
                  celestia:newframe("planetographic", body):from(celestia:newposition(x, y, z), endtime)
            end
            token_is_longlat = false
         elseif token == "above" then
            distance_factor = 1.1
         elseif token == "antipodal" or token == "antipous" then
            angle = angle + 180
         elseif token == "covisual" then
            angle = angle + 173
            distance_factor = 9
         elseif token == "diagonal" then
            angle = angle - 45
         elseif token == "left" then
            angle_factor = -1
         elseif token == "longlat" then
             token_is_longlat=true
         elseif token == "pole" then
            if body == nil then
               celestia:flash("Illegial location: pole without body\in: " .. travel_parms.location, 60);wait(60);
               error(2)
            end
            local distance = reference_position:distanceto(goto_position)
            reference_position =
               celestia:newframe("planetographic", body):from(celestia:newposition(.001, distance, 0), endtime)
         elseif token == "terminator" then
            angle = angle - 89
         elseif token == "viewing" then
            viewing = true
         elseif string.sub(token, -2) == "au" and token_value ~= nil then
            viewing = true
            viewing_AU = token_value
         elseif string.sub(token, -2) == "km" and token_value ~= nil then
            viewing = true
            viewing_AU = token_value / KM_PER_AU
         elseif string.sub(token, -1) == "r" and tonumber(string.sub(token, 1, -2)) ~= nil then
            viewing = true
            viewing_AU = body_radius * tonumber(string.sub(token, 1, -2)) / KM_PER_AU
         elseif ignore_tokens[token] == nil then
            celestia:flash("Unknown location word: " .. token .. "\nin: " .. travel_parms.location, 60);wait(60);
            error(3)
         end
      end
   end
   
   -- calculate the endposition: coordinates to travel to
   local vector_endpoint_to_reference = reference_position - goto_position
   local normalised_vector_endpoint_to_reference = vector_endpoint_to_reference:normalize()
   local vector_from_endpoint_towards_reference
   if viewing then
      vector_from_endpoint_towards_reference = viewing_AU / AU_PER_uLY * normalised_vector_endpoint_to_reference
   else
      vector_from_endpoint_towards_reference =
         (body_radius * distance_factor) / KM_PER_uLY * normalised_vector_endpoint_to_reference
   end
   local desired_rotation = celestia:newrotation(body_up, math.rad(angle * angle_factor))
   local endposition = goto_position + desired_rotation:transform(vector_from_endpoint_towards_reference)
   
   -- calc_only = don't travel, just return the destination coordinates
   if travel_parms.calc_only == true then
      return endposition
   end
   
   -- intial_tracking = object to watch as we start the journey
   if initial_tracking ~= nil then
      if type(initial_tracking) == "string" then
         initial_tracking = celestia:find(initial_tracking)
      end
   end
   
   -- determine what direction we should face at the start of the journey, and how long to devote to turning to that
   -- direction
   if initial_tracking ~= nil or initial_orientation ~= nil then
      -- shave up to 3 seconds or 10% off the the total travel time to spend turning to the initial_tracking object or
      -- initial_orientation
      local look_vector = celestia:newvector(0,0,-1)
      local current_look_vector   = (obs:getorientation():transform(look_vector)):normalize()
      local current_up_vector      = (obs:getorientation():transform(UP)):normalize()
      local desired_look_vector
      local desired_up_vector
      if initial_tracking == nil then
         desired_look_vector   = (initial_orientation:transform(look_vector)):normalize()
         desired_up_vector      = (initial_orientation:transform(UP)):normalize()
      else
         desired_look_vector   = (initial_tracking:getposition() - obs:getposition()):normalize()
         desired_up_vector      = current_up_vector
      end
      -- see if we are looking in the desired direction, if not, determine how much we have to turn and how long
      -- to allow in doing so
      local screenh, screenv = celestia:getscreendimension()
      if (current_look_vector - desired_look_vector):length() > 1e-8 then
         local vpixels_from_centre = screenv * math.acos(current_look_vector * desired_look_vector) / obs:getfov()
         centre_time = math.min(vpixels_from_centre / vpixels_per_sec, travel_time * 0.1, 3)
      end
      -- see if we need to roll.
      if (current_up_vector - desired_up_vector):length() > 1e-8 then
         local radians_to_roll = math.acos(current_up_vector * desired_up_vector)
         local roll_time = math.min(radians_to_roll / radians_per_sec, travel_time * 0.1, 3)
         centre_time = math.max(centre_time, roll_time)
      end
   end
   
   -- final_tracking = object to watch as we end the journey
   if final_tracking ~= nil then
      if type(final_tracking) == "string" then
         final_tracking = celestia:find(final_tracking)
      end
   end
   -- recalculate the time to actually be spent travelling
   travel_time = travel_time - centre_time
   
   -- if we are already near the endpoint and there is no timetravel involved then shorten the journey time.
   if travel_parms.at == nil and travel_parms.adjust_time ~= false then
      local tolerance
      if body == nil then
         tolerance = obs:getposition():distanceto(celestia:newposition(0,0,0)) * .02
      else
         tolerance = obs:getposition():distanceto(body:getposition()) * .02
      end
      local travel_distance = obs:getposition():distanceto(endposition)
      if travel_distance < tolerance then
         local new_travel_time = travel_distance / tolerance
         if new_travel_time < travel_time then
            travel_time = new_travel_time
         end
      end
   end
   
   -- start applying changes to the observer
   -- first, display data about the body
   if body ~= nil then
      celestia:select(travel_parms.body)
   end
   -- centre the body to be initially tracked on the screen
   if initial_tracking ~= nil then
      initial_tracking:preloadtexture()
      if initial_tracking:getinfo().parent ~= nil then
         -- to load the planet for moons, satellites, etc.
         initial_tracking:getinfo().parent:preloadtexture()
      end
      obs:track(nil)
      obs:center(initial_tracking, centre_time)
      wait(centre_time)
      obs:track(initial_tracking)
   end
   -- turn to the initial_orientation
   if initial_orientation ~= nil and centre_time > 0 then
      local start_orientation = obs:getorientation()
      local end_reorient_scripttime = celestia:getscripttime() + centre_time
      local reorient_percent = 1
      while reorient_percent > 0 do
         wait(0.0)
         reorient_percent = math.max((end_reorient_scripttime - celestia:getscripttime()) / centre_time, 0)
         obs:setorientation(initial_orientation:slerp(start_orientation, reorient_percent))
      end
   end
   
   -- final calculations before we travel...
      -- Note: Measurements are made relative to the endstate, not the startstate.  This is so that multiplicative
      --       errors will reduce to 0 as we approach the endstate, rather than increase as we get farther from the
      --         startstate
      -- Note: accel/decel math is implemented as follows
      --         j:      jerk (acceleration of acceleration)
      --         a:      acceleration                         ia:   initial acceleration
      --         s:      speed                                 is:   initial speed
      --         d:      distance from origin                  id:   initial distance from origin
      --         acceleration at time t:
      --            a[t] = j t + ia
      --         the antiderivative of acceleration is speed s (not velocity):
      --            s[t] = .5 j t^2 + ia t + is
      --         the antiderivative of speed is displacement (which I am calling distance for convenience):
      --            d[t] = j t^3 / 6 + .5 ia t^2 + is t + id
      --         (can someone please check my unused-for-20-years calculus?)
      --         since we are considering the observer's current position as the starting point of the journey: id = 0
      --         since we are not accounting for the observer's current motion: is = 0
      --         therefore:
      --            s[t] = .5 j t^2 + ia t + 0 = .5 j t^2 + ia t
      --            d[t] = j t^3 / 6 + .5 ia t^2 + 0 t + 0 = j t^3 / 6 + .5 ia t^2
      --       D:    total travel distance               T:      total travel time
      --         da:   total distance spent accelerating   ta:   total time spent accelerating
      --         dc:   total distance spent cruising         tc:   total time spent cruising
      --         dd:   total distance spend decelerating   td:   total time spent decelerating
      --         d[t]:   distance covered by time t
      --         da[t]: distance covered in acceleration phase by time t   ta[t] = total time spent accelerating at time t
      --         dc[t]: distance covered in cruising phase by time t      tc[t] = total time spent cruising at time t
      --         dd[t]: distance covered in deceleration phase by time t   td[t] = total time spent decelerating at time t
      --            tc = T - ta - td ; td = ta ; tc = T - 2 ta
      --            da = d[ta] = j ta^3 / 6 + .5 ia ta^2
      --            dc = cruising speed * time cruising = speed after acceleration * time cruising
      --               = s[ta] tc = (.5 j ta^2 + ia ta) tc = .5 j tc ta^2 + ia tc ta
      --            dd = d[ta] = j ta^3 / 6 + .5 ia ta^2
      --            D = da + dc + dd = j ta^3 / 6 + .5 ia ta^2 + .5 j tc ta^2 + ia tc ta + j ta^3 / 6 + .5 ia ta^2
      --         if constant acceleration is to be used ( { accel=true } ), then j = 0 and ia is determined as follows:
      --          D = 0 + .5 ia ta^2 + 0 + ia tc ta + 0 + .5 ia ta^2 = ia ta^2 + ia tc ta = ia (ta^2 + tc ta)
      --          ia = D / (ta^2 + tc ta)
      --       if accelerating acceleration is to be used ( { jerk=true } ), then ia = 0 and j is determined as follows:
      --            D = j ta^3 / 6 + 0 + .5 j tc ta^2 + 0 + j ta^3 / 6 + 0
      --            = j (ta^3 / 3 + .5 tc ta^2)
      --            j = D / (ta^3 / 3 + .5 tc ta^2)
      --         when d and t are percentages of D and T then D = 1 and T = 1, therefore
      --            tc = 1 - 2 ta
      --          ta[t] = min(t, ta)
      --            tc[t] = min(max(t - ta, 0), tc)
      --            td[t] = max(t - ta - tc, 0) = max(t - ta - (1 - 2 ta), 0) =  max(t - 1 + ta, 0)
      --            da[t] = j ta[t]^3 / 6 + .5 ia ta[t]^2
      --            dc[t] = .5 j tc[t] ta[t]^2 + ia ta tc[t]
      --          dd[t] = dd - (j (td - td[t])^3 / 6 + .5 ia (td - td[t])^2)
      --                = j ta^3 / 6 + .5 ia ta^2 - j (td - td[t])^3 / 6 - .5 ia (td - td[t])^2
      --                = j (ta^3 - (td - td[t])^3) / 6 + .5 ia(ta^2  - (td - td[t])^2)
      --            d[t] = da[t] + dc[t] + dt[t] > 0 ? dd[t] : 0
      --       when t is changed to measure from 1 (start of journey) to 0, end of journey, then
      --            ta[t] = 1 - max(1 - ta, t)
      --            td[t] = td - min(td, t) = ta - min(ta, t)
      --            tc[t] = 1 - t - ta[t] - td[t]
   local accel_percent = travel_parms.accelTime   -- = ta
   if accel_percent == nil then
      accel_percent = .25
   end
   accel_percent = math.min(math.max(accel_percent, .001), .5)
   local cruise_percent = 1 - 2 * accel_percent   -- = tc
   local jerk, acceleration                     -- = j, ia
   local use_jerk = travel_parms.jerk
   if use_jerk == nil then
      use_jerk = TRAVEL_TO_JERK
      if use_jerk == nil then
         use_jerk = true
      end
   end
   if use_jerk then
      jerk = 1 / ((accel_percent^3) / 3 + .5 * cruise_percent * accel_percent^2)
      acceleration = 0
   else
      jerk = 0
      acceleration = 1 / (accel_percent^2 + cruise_percent * accel_percent)
   end
   local current_up_vector = (obs:getorientation():transform(UP)):normalize()
   local timechange = endtime - obs:gettime()
   local end_scripttime = celestia:getscripttime() + travel_time
   local travel_vector = obs:getposition() - endposition
   local start_interpolation_orientation, end_interpolation_orientation
   local time_percent = 1                                                   -- = t
   local accel_time_percent, cruise_time_percent, decel_time_percent         -- = tat, tct, tdt
   local accel_dist_percent, cruise_dist_percent, decel_dist_percent         -- = da[t], dc[t], dd[t]
   local distance_percent                                                   -- = dt
   -- end_ and start_interpolation are measured from the start of the journey, change them to measure from the end
   end_interpolation = 1 - end_interpolation
   start_interpolation = 1 - start_interpolation

   -- final rotational calculations
   local interpolation_started = false
   local interpolation_ended = false
   local need_final_up = (final_up ~= nil)
   if final_orientation == nil then
      if final_tracking == nil or end_interpolation == 1 then
         end_interpolation_orientation = obs:getorientation()
      else
         -- where will we be when it is time to stop turning the observer (ei), and where should the observer point to?
         accel_time_percent = math.min(end_interpolation, accel_percent)                                       -- ta[ei]
         cruise_time_percent = math.min(math.max(end_interpolation - accel_percent, 0), cruise_percent)         -- tc[ei]
         decel_time_percent = math.max(end_interpolation - 1 + accel_percent, 0)                                 -- td[ei]
         accel_dist_percent = (jerk * accel_time_percent^3) / 6 + .5 * acceleration * accel_time_percent^2      -- da[ei]
         cruise_dist_percent = .5 * jerk * cruise_time_percent * accel_time_percent^2 +
                               acceleration * accel_percent * cruise_time_percent                              -- dc[ei]
         decel_dist_percent = jerk * (accel_percent^3 - (accel_percent - decel_time_percent)^3) / 6 +          -- dd[ei]
                                .5 * acceleration * (accel_percent^2  - (accel_percent - decel_time_percent)^2)
         distance_percent = accel_dist_percent + cruise_dist_percent + decel_dist_percent                        -- dt[ei]
         local end_interpolation_position = endposition + travel_vector * distance_percent
         local end_interpolation_time
         if travel_parms.at == nil then
            -- no at given: time change is linear
            end_interpolation_time = endtime - timechange * end_interpolation
         else
            -- with at, time change will accel/cruise/decel
            end_interpolation_time = endtime - timechange * distance_percent
         end
         local final_up_vector = current_up_vector
         if need_final_up then
            final_up_vector = final_up
            need_final_up = false
         end
         end_interpolation_orientation =
            end_interpolation_position:orientationto(final_tracking:getposition(end_interpolation_time),
                                                     final_up_vector)
      end
      if need_final_up then
         -- we still need to rotate the final orientation so that final_up will point to the top of the screen
         local origin = celestia:newposition(0,0,0)
         local look_vector = celestia:newvector(0,0,-1)
         local final_look_vector   = (end_interpolation_orientation:transform(look_vector)):normalize()
         end_interpolation_orientation = origin:orientationto(origin + final_look_vector, final_up)
      end
   else
      end_interpolation_orientation = final_orientation
   end
   local interpolation_duration = start_interpolation - end_interpolation
   
   -- do the actual travelling
   while time_percent > 0 do
      time_percent = math.max((end_scripttime - celestia:getscripttime()) / travel_time, 0)               -- t
      accel_time_percent = math.min(time_percent, accel_percent)                                          -- ta[t]
      cruise_time_percent = math.min(math.max(time_percent - accel_percent, 0), cruise_percent)            -- tc[t]
      decel_time_percent = math.max(time_percent - 1 + accel_percent, 0)                                 -- td[tei]
      accel_dist_percent = (jerk * accel_time_percent^3) / 6 + .5 * acceleration * accel_time_percent^2   -- da[t]
      cruise_dist_percent = .5 * jerk * cruise_time_percent * accel_time_percent^2 +
                            acceleration * accel_percent * cruise_time_percent                           -- dc[t]
      decel_dist_percent = jerk * (accel_percent^3 - (accel_percent - decel_time_percent)^3) / 6 +         -- dd[t]
                           .5 * acceleration * (accel_percent^2  - (accel_percent - decel_time_percent)^2)
      distance_percent = accel_dist_percent + cruise_dist_percent + decel_dist_percent                     -- dt[t]
      --celestia:flash(string.format("j=%3.3f a=%3.3f\nt[%1.4f] = %1.4f + %1.4f + %1.4f\ndt[%1.4f] = %1.4f + %1.4f + %1.4f",
      --                       jerk, acceleration,
      --                       time_percent, accel_time_percent, cruise_time_percent, decel_time_percent,
      --                       distance_percent, accel_dist_percent, cruise_dist_percent, decel_dist_percent))
      obs:setposition(endposition + travel_vector * distance_percent)
      if travel_parms.at == nil then
         celestia:settime(endtime - timechange * time_percent) -- no at given: time change is linear
      else
         celestia:settime(endtime - timechange * distance_percent) -- with at, time change will accel/cruise/decel
      end
      if time_percent > end_interpolation then
         if start_interpolation > time_percent then
            if interpolation_started == false then
               start_interpolation_orientation = obs:getorientation()
               obs:track(nil)
               interpolation_started = true
            end
            obs:setorientation(end_interpolation_orientation:slerp(start_interpolation_orientation,
                               (time_percent - end_interpolation) / interpolation_duration))
         end
      elseif interpolation_ended == false then
         obs:setorientation(end_interpolation_orientation)
         obs:track(final_tracking)
         interpolation_ended = true
      end
      wait(0.0)
   end
   
   -- re-set the endstates (for accuraccy)
   celestia:settime(endtime)
   obs:setposition(endposition)
   wait(0.0)

   obs:track(nil)
   if body ~= nil then
      obs:follow(body)
   end
end -- travel_to()

Re: goto always to sunny face of planet

Posted: 18.06.2009, 21:37
by cpotting
oops. I missed the definition of some constants that are needed:

Code: Select all

   KM_PER_AU     = 149597870.7
   KM_PER_uLY    = 9466411.842
   AU_PER_uLY    = (KM_PER_uLY / KM_PER_AU)
   SEC_PER_JDAY  = 86400
   DAYS_PER_YR   = 365.2624
   c_uLY_PER_SEC = 1000000 / (SEC_PER_JDAY * DAYS_PER_YR)
   UP            = celestia:newvector(0,1,0)
   ALMOST_UP     = celestia:newvector(0.000001,1,0) -- used to avoid positioning an observer so it is looking in the
                                                    -- exact direction of a frame's UP vector (which causes display
                                                    -- problems)
   ALMOST_ABOVE  = celestia:newposition(0.000001,1,0) -- ALMOST_UP described as a position - useful in limited cases

Re: goto always to sunny face of planet

Posted: 19.06.2009, 15:54
by Vincent
loberlat wrote:Second, I have to go to a planete, to its sunny side, ans accelerate time to make it one complete turn in 10 seconds.
Hi,

The following celx script moves the observer to a position located on the Planet-Sun axis.
Just replace Earth with the needed planet in the first line of the script.

Code: Select all

target = celestia:find("Sol/Earth")
star = celestia:find("Sol")
distance = target:radius() * 5

v = (star:getposition() - target:getposition()):normalize()
coeff = distance / 1e7
pos = celestia:newposition(v.x * coeff, v.y * coeff, v.z * coeff)

obs = celestia:getobserver()
celestia:select(target)

obs:gotodistance(target, distance, 5)
wait(5)

obs:track(target)
obs:gotolocation(pos, 5)
wait(6)

obs:track(nil)