scriptorbit.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:8k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // scriptorbit.cpp
  2. //
  3. // Copyright (C) 2006, Chris Laurel <claurel@shatters.net>
  4. //
  5. // Interface for a Celestia trajectory implemented via a Lua script.
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. #include <cstdio>
  12. #include <cassert>
  13. #include "scriptobject.h"
  14. #include "scriptorbit.h"
  15. using namespace std;
  16. ScriptedOrbit::ScriptedOrbit() :
  17.     luaState(NULL),
  18.     boundingRadius(1.0),
  19.     period(0.0),
  20.     validRangeBegin(0.0),
  21.     validRangeEnd(0.0)
  22. {
  23. }
  24. ScriptedOrbit::~ScriptedOrbit()
  25. {
  26. }
  27. /*! Initialize the script orbit.
  28.  *  moduleName is the name of a module that contains the orbit factory
  29.  *  function. The module will be loaded with Lua's require function before
  30.  *  creating the Lua orbit object.
  31.  *
  32.  *  funcName is the name of some factory function in the specified luaState
  33.  *  that will produce a Lua orbit object from the parameter list.
  34.  *
  35.  *  The Lua factory function accepts a single table parameter containg
  36.  *  all the orbit properties. It returns a table with the following
  37.  *  properties:
  38.  *
  39.  *      boundingRadius - A number giving the maximum distance of the trajectory
  40.  *         from the origin; must be present, and must be a positive value.
  41.  *      period - A number giving the period of the orbit. If not present,
  42.  *         the orbit is assumed to be aperiodic. The orbital period is only
  43.  *         used for drawing the orbit path.
  44.  *      beginDate, endDate - optional values that specify the time span over
  45.  *         which the orbit is valid. If not given, the orbit is assumed to be
  46.  *          useable at any time. The orbit is invalid if end < begin.
  47.  *      position(time) - The position function takes a time value as input
  48.  *         (TDB Julian day) and returns three values which are the x, y, and
  49.  *         z coordinates. Units for the position are kilometers.
  50.  */
  51. bool
  52. ScriptedOrbit::initialize(const std::string& moduleName,
  53.                           const std::string& funcName,
  54.                           Hash* parameters)
  55. {
  56.     if (parameters == NULL)
  57.         return false;
  58.     luaState = GetScriptedObjectContext();
  59.     if (luaState == NULL)
  60.     {
  61.         clog << "ScriptedOrbits are currently disabled.n";
  62.         return false;
  63.     }
  64.     if (!moduleName.empty())
  65.     {
  66.         lua_pushstring(luaState, "require");
  67.         lua_gettable(luaState, LUA_GLOBALSINDEX);
  68.         if (!lua_isfunction(luaState, -1))
  69.         {
  70.             clog << "Cannot load ScriptedOrbit package: 'require' function is unavailablen";
  71.             lua_pop(luaState, 1);
  72.             return false;
  73.         }
  74.         lua_pushstring(luaState, moduleName.c_str());
  75.         if (lua_pcall(luaState, 1, 1, 0) != 0)
  76.         {
  77.             clog << "Failed to load module for ScriptedOrbit: " << lua_tostring(luaState, -1) << "n";
  78.             lua_pop(luaState, 1);
  79.             return false;
  80.         }
  81.     }
  82.     // Get the orbit generator function
  83.     lua_pushstring(luaState, funcName.c_str());
  84.     lua_gettable(luaState, LUA_GLOBALSINDEX);
  85.     if (lua_isfunction(luaState, -1) == 0)
  86.     {
  87.         // No function with the requested name; pop whatever value we
  88.         // did receive along with the table of arguments.
  89.         lua_pop(luaState, 1);
  90.         clog << "No Lua function named " << funcName << " found.n";
  91.         return false;
  92.     }
  93.     // Construct the table that we'll pass to the orbit generator function
  94.     lua_newtable(luaState);
  95.     // Convert all the parameters in the list to their equivalent Lua
  96.     // types and insert them into the table. Presently, only number, string,
  97.     // and boolean values are converted.
  98.     for (HashIterator iter = parameters->begin(); iter != parameters->end();
  99.          iter++)
  100.     {
  101.         switch (iter->second->getType())
  102.         {
  103.         case Value::NumberType:
  104.             lua_pushstring(luaState, iter->first.c_str());
  105.             lua_pushnumber(luaState, iter->second->getNumber());
  106.             lua_settable(luaState, -3);
  107.             break;
  108.         case Value::StringType:
  109.             lua_pushstring(luaState, iter->first.c_str());
  110.             lua_pushstring(luaState, iter->second->getString().c_str());
  111.             lua_settable(luaState, -3);
  112.             break;
  113.         case Value::BooleanType:
  114.             lua_pushstring(luaState, iter->first.c_str());
  115.             lua_pushboolean(luaState, iter->second->getBoolean());
  116.             lua_settable(luaState, -3);
  117.             break;
  118.         default:
  119.             break;
  120.         }
  121.     }
  122.     // Call the generator function
  123.     if (lua_pcall(luaState, 1, 1, 0) != 0)
  124.     {
  125.         // Some sort of error occurred--the error message is atop the stack
  126.         clog << "Error calling ScriptedOrbit generator function: " <<
  127.             lua_tostring(luaState, -1) << "n";
  128.         lua_pop(luaState, 1);
  129.         return false;
  130.     }
  131.     if (lua_istable(luaState, -1) == 0)
  132.     {
  133.         // We have an object, but it's not a table. Pop it off the
  134.         // stack and report failure.
  135.         clog << "ScriptedOrbit generator function returned bad value.n";
  136.         lua_pop(luaState, 1);
  137.         return false;
  138.     }
  139.     luaOrbitObjectName = GenerateScriptObjectName();
  140.     // Attach the name to the script orbit
  141.     lua_pushstring(luaState, luaOrbitObjectName.c_str());
  142.     lua_pushvalue(luaState, -2); // dup the orbit object on top of stack
  143.     lua_settable(luaState, LUA_GLOBALSINDEX);
  144.     // Now, call orbit object methods to get the bounding radius
  145.     // and valid time range.
  146.     lua_pushstring(luaState, "boundingRadius");
  147.     lua_gettable(luaState, -2);
  148.     if (lua_isnumber(luaState, -1) == 0)
  149.     {
  150.         clog << "Bad or missing boundingRadius for ScriptedOrbit objectn";
  151.         lua_pop(luaState, 1);
  152.         return false;
  153.     }
  154.     boundingRadius = lua_tonumber(luaState, -1);
  155.     lua_pop(luaState, 1);
  156.     // Get the rest of the orbit parameters; they are all optional.
  157.     period          = SafeGetLuaNumber(luaState, -1, "period", 0.0);
  158.     validRangeBegin = SafeGetLuaNumber(luaState, -1, "beginDate", 0.0);
  159.     validRangeEnd   = SafeGetLuaNumber(luaState, -1, "endDate", 0.0);
  160.     // Pop the orbit object off the stack
  161.     lua_pop(luaState, 1);
  162.     // Perform some sanity checks on the orbit parameters
  163.     if (validRangeEnd < validRangeBegin)
  164.     {
  165.         clog << "Bad script orbit: valid range end < beginn";
  166.         return false;
  167.     }
  168.     if (boundingRadius <= 0.0)
  169.     {
  170.         clog << "Bad script object: bounding radius must be positiven";
  171.         return false;
  172.     }
  173.     return true;
  174. }
  175. // Call the position method of the ScriptedOrbit object
  176. Point3d
  177. ScriptedOrbit::computePosition(double tjd) const
  178. {
  179.     Point3d pos(0.0, 0.0, 0.0);
  180.     lua_pushstring(luaState, luaOrbitObjectName.c_str());
  181.     lua_gettable(luaState, LUA_GLOBALSINDEX);
  182.     if (lua_istable(luaState, -1))
  183.     {
  184.         lua_pushstring(luaState, "position");
  185.         lua_gettable(luaState, -2);
  186.         if (lua_isfunction(luaState, -1))
  187.         {
  188.             lua_pushvalue(luaState, -2); // push 'self' on stack
  189.             lua_pushnumber(luaState, tjd);
  190.             if (lua_pcall(luaState, 2, 3, 0) == 0)
  191.             {
  192.                 pos.x = lua_tonumber(luaState, -3);
  193.                 pos.y = lua_tonumber(luaState, -2);
  194.                 pos.z = lua_tonumber(luaState, -1);
  195.                 lua_pop(luaState, 3);
  196.             }
  197.             else
  198.             {
  199.                 // Function call failed for some reason
  200.                 //clog << "ScriptedOrbit failed: " << lua_tostring(luaState, -1) << "n";
  201.                 lua_pop(luaState, 1);
  202.             }
  203.         }
  204.         else
  205.         {
  206.             // Bad position function
  207.             lua_pop(luaState, 1);
  208.         }
  209.     }
  210.     else
  211.     {
  212.         // The script orbit object disappeared. OOPS.
  213.     }
  214.     // Pop the script orbit object
  215.     lua_pop(luaState, 1);
  216.     // Convert to Celestia's internal coordinate system
  217.     return Point3d(pos.x, pos.z, -pos.y);
  218. }
  219. double
  220. ScriptedOrbit::getPeriod() const
  221. {
  222.     if (period == 0.0)
  223.     {
  224.         return validRangeEnd - validRangeBegin;
  225.     }
  226.     else
  227.     {
  228.         return period;
  229.     }
  230. }
  231. bool
  232. ScriptedOrbit::isPeriodic() const
  233. {
  234.     return period != 0.0;
  235. }
  236. void
  237. ScriptedOrbit::getValidRange(double& begin, double& end) const
  238. {
  239.     begin = validRangeBegin;
  240.     end = validRangeEnd;
  241. }
  242. double
  243. ScriptedOrbit::getBoundingRadius() const
  244. {
  245.     return boundingRadius;
  246. }