#include <Systems/system_mgr.hxx>
#include <Time/FGEventMgr.hxx>
#include <Time/light.hxx>
-#include <Time/sunpos.hxx>
#include <Time/moonpos.hxx>
+#include <Time/sunpos.hxx>
+#include <Time/sunsolver.hxx>
#include <Time/tmp.hxx>
#ifdef FG_MPLAYER_AS
zone.str(),
cur_time_override->getLongValue() );
+ globals->set_warp_delta( 0 );
+
+ t->update( 0.0, 0.0,
+ cur_time_override->getLongValue(),
+ globals->get_warp() );
+
+ return t;
+}
+
+
+// set up a time offset (aka warp) if one is specified
+void fgInitTimeOffset() {
+ static const SGPropertyNode *longitude
+ = fgGetNode("/position/longitude-deg");
+ static const SGPropertyNode *latitude
+ = fgGetNode("/position/latitude-deg");
+ static const SGPropertyNode *cur_time_override
+ = fgGetNode("/sim/time/cur-time-override", true);
+
// Handle potential user specified time offsets
+ SGTime *t = globals->get_time_params();
time_t cur_time = t->get_cur_time();
time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
time_t aircraftLocalTime =
sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
- // Okay, we now have six possible scenarios
+ // Okay, we now have several possible scenarios
int offset = fgGetInt("/sim/startup/time-offset");
+ int warp = 0;
const string &offset_type = fgGetString("/sim/startup/time-offset-type");
- if (offset_type == "system-offset") {
- globals->set_warp( offset );
- } else if (offset_type == "gmt-offset") {
- globals->set_warp( offset - (currGMT - systemLocalTime) );
- } else if (offset_type == "latitude-offset") {
- globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) );
- } else if (offset_type == "system") {
- globals->set_warp( offset - cur_time );
- } else if (offset_type == "gmt") {
- globals->set_warp( offset - currGMT );
- } else if (offset_type == "latitude") {
- globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) -
- cur_time );
+ if ( offset_type == "noon" ) {
+ warp = fgTimeSecondsUntilNoon( cur_time,
+ longitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS,
+ latitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS );
+ } else if ( offset_type == "midnight" ) {
+ warp = fgTimeSecondsUntilMidnight( cur_time,
+ longitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS,
+ latitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS );
+ } else if ( offset_type == "dawn" ) {
+ warp = fgTimeSecondsUntilDawn( cur_time,
+ longitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS,
+ latitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS );
+ } else if ( offset_type == "dusk" ) {
+ warp = fgTimeSecondsUntilDusk( cur_time,
+ longitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS,
+ latitude->getDoubleValue()
+ * SGD_DEGREES_TO_RADIANS );
+ } else if ( offset_type == "system-offset" ) {
+ warp = offset;
+ } else if ( offset_type == "gmt-offset" ) {
+ warp = offset - (currGMT - systemLocalTime);
+ } else if ( offset_type == "latitude-offset" ) {
+ warp = offset - (aircraftLocalTime - systemLocalTime);
+ } else if ( offset_type == "system" ) {
+ warp = offset - cur_time;
+ } else if ( offset_type == "gmt" ) {
+ warp = offset - currGMT;
+ } else if ( offset_type == "latitude" ) {
+ warp = offset - (aircraftLocalTime - systemLocalTime) - cur_time;
} else {
SG_LOG( SG_GENERAL, SG_ALERT,
"FG_TIME::Unsupported offset type " << offset_type );
exit( -1 );
}
+ globals->set_warp( warp );
+ t->update( 0.0, 0.0, cur_time_override->getLongValue(),
+ globals->get_warp() );
- SG_LOG( SG_GENERAL, SG_INFO, "After time init, warp = "
+ SG_LOG( SG_GENERAL, SG_INFO, "After fgInitTimeOffset(): warp = "
<< globals->get_warp() );
- globals->set_warp_delta( 0 );
-
- t->update( 0.0, 0.0,
- cur_time_override->getLongValue(),
- globals->get_warp() );
-
- return t;
+ fgUpdateSkyAndLightingParams();
}
-
// This is the top level init routine which calls all the other
// initialization routines. If you are adding a subsystem to flight
// gear, its initialization call should located in this routine.
// returns a new instance of the SGTime class
SGTime *fgInitTime();
+// set up a time offset (aka warp) if one is specified
+void fgInitTimeOffset();
+
+
#endif // _FG_INIT_HXX
// Update solar system
globals->get_ephem()->update( globals->get_time_params()->getMjd(),
- globals->get_time_params()->getLst(),
- cur_fdm_state->get_Latitude() );
+ globals->get_time_params()->getLst(),
+ cur_fdm_state->get_Latitude() );
// Update radio stack model
current_radiostack->update(delta_time_sec);
idle_state++;
} else if ( idle_state == 4 ) {
+ // Initialize the time offset (warp) after fgInitSubsystem
+ // (which initializes the lighting interpolation tables.)
+ fgInitTimeOffset();
+
// setup OpenGL view parameters
fgInitVisuals();
idle_state++;
} else if ( idle_state == 6 ) {
// sleep(1);
+
+ fgUpdateSkyAndLightingParams();
+
idle_state = 1000;
SG_LOG( SG_GENERAL, SG_INFO, "Panel visible = " << fgPanelVisible() );
ephem_data_path.append( "Astro" );
SGEphemeris *ephem = new SGEphemeris( ephem_data_path.c_str() );
ephem->update( globals->get_time_params()->getMjd(),
- globals->get_time_params()->getLst(),
- 0.0 );
+ globals->get_time_params()->getLst(),
+ 0.0 );
globals->set_ephem( ephem );
- // TODO: move to environment mgr
+ // TODO: move to environment mgr
thesky = new SGSky;
SGPath texture_path(globals->get_fg_root());
texture_path.append("Textures");
thesky->add_cloud_layer(layer);
}
-
SGPath sky_tex_path( globals->get_fg_root() );
sky_tex_path.append( "Textures" );
sky_tex_path.append( "Sky" );
{"bpp", true, OPTION_FUNC, "", false, "", fgOptBpp },
{"units-feet", false, OPTION_STRING, "/sim/startup/units", false, "feet", 0 },
{"units-meters", false, OPTION_STRING, "/sim/startup/units", false, "meters", 0 },
+ {"timeofday", true, OPTION_STRING, "/sim/startup/time-offset-type", false, "noon", 0 },
{"time-offset", true, OPTION_FUNC, "", false, "", fgOptTimeOffset },
{"time-match-real", false, OPTION_STRING, "/sim/startup/time-offset-type", false, "system-offset", 0 },
{"time-match-local", false, OPTION_STRING, "/sim/startup/time-offset-type", false, "latitude-offset", 0 },
_selector(new ssgSelector),
_scene(new ssgRoot),
_nearplane(0.01f),
- _farplane(100.0f)
+ _farplane(1000.0f)
{
}
light.cxx light.hxx \
moonpos.cxx moonpos.hxx \
sunpos.cxx sunpos.hxx \
+ sunsolver.cxx sunsolver.hxx \
tmp.cxx tmp.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
void fgMoonPosition(time_t ssue, double *lon, double *lat);
-#endif /* _MOONPOS_H */
+#endif /* _MOONPOS_HXX */
* meridian (GST), compute position on the earth (lat, lon) such that
* sun is directly overhead. (lat, lon are reported in radians */
-static void fgSunPositionGST(double gst, double *lon, double *lat) {
+void fgSunPositionGST(double gst, double *lon, double *lat) {
/* time_t ssue; seconds since unix epoch */
/* double *lat; (return) latitude */
/* double *lon; (return) longitude */
globals->get_ephem()->get_sun()->getLat(),
&alpha, &delta );
-// tmp = alpha - (SGD_2PI/24)*GST(ssue);
+ // tmp = alpha - (SGD_2PI/24)*GST(ssue);
tmp = alpha - (SGD_2PI/24)*gst;
if (tmp < -SGD_PI) {
do tmp += SGD_2PI;
void fgSunPosition(time_t ssue, double *lon, double *lat);
+/* given a particular time expressed in side real time at prime
+ * meridian (GST), compute position on the earth (lat, lon) such that
+ * sun is directly overhead. (lat, lon are reported in radians */
+void fgSunPositionGST(double gst, double *lon, double *lat);
-#endif /* _SUNPOS_H */
+
+#endif /* _SUNPOS_HXX */
--- /dev/null
+/*
+ * sunsolver.cxx - given a location on earth and a time of day/date,
+ * find the number of seconds to various sun positions.
+ *
+ * Written by Curtis Olson, started September 2003.
+ *
+ * Copyright (C) 2003 Curtis L. Olson - curt@flightgear.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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+
+#include <simgear/math/point3d.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/timing/sg_time.hxx>
+
+#include <Main/globals.hxx>
+
+#include "sunpos.hxx"
+
+#include "sunsolver.hxx"
+
+
+const time_t day_secs = 86400;
+
+static double sun_angle( const SGTime &t, sgVec3 world_up,
+ double lon_rad, double lat_rad ) {
+ sgVec3 nup, nsun;
+ Point3D p, rel_sunpos;
+
+ SG_LOG( SG_EVENT, SG_DEBUG, " Updating Sun position" );
+ SG_LOG( SG_EVENT, SG_DEBUG, " Gst = " << t.getGst() );
+
+ double sun_lon, sun_gd_lat, sun_gc_lat, sl_radius;
+ fgSunPositionGST( t.getGst(), &sun_lon, &sun_gd_lat );
+
+ sgGeodToGeoc(sun_gd_lat, 0.0, &sl_radius, &sun_gc_lat);
+
+ p = Point3D( sun_lon, sun_gc_lat, sl_radius );
+ Point3D sunpos = sgPolarToCart3d(p);
+
+ SG_LOG( SG_EVENT, SG_DEBUG, " t.cur_time = " << t.get_cur_time() );
+ SG_LOG( SG_EVENT, SG_DEBUG,
+ " Sun Geodetic lat = " << sun_gd_lat
+ << " Geocentric lat = " << sun_gc_lat );
+
+ // calculate the sun's relative angle to local up
+ sgCopyVec3( nup, world_up );
+ sgSetVec3( nsun, sunpos.x(), sunpos.y(), sunpos.z() );
+ sgNormalizeVec3(nup);
+ sgNormalizeVec3(nsun);
+ // cout << "nup = " << nup[0] << "," << nup[1] << ","
+ // << nup[2] << endl;
+ // cout << "nsun = " << nsun[0] << "," << nsun[1] << ","
+ // << nsun[2] << endl;
+
+ double sun_angle = acos( sgScalarProductVec3 ( nup, nsun ) );
+ double sun_angle_deg = sun_angle * SG_RADIANS_TO_DEGREES;
+ while ( sun_angle_deg < -180 ) { sun_angle += 360; }
+ SG_LOG( SG_EVENT, SG_DEBUG, "sun angle relative to current location = "
+ << sun_angle_deg );
+
+ return sun_angle_deg;
+}
+
+
+/**
+ * Given the current unix time in seconds, calculate seconds to noon
+ */
+time_t fgTimeSecondsUntilNoon( time_t cur_time,
+ double lon_rad,
+ double lat_rad )
+{
+ // cout << "location = " << lon_rad * SG_RADIANS_TO_DEGREES << ", "
+ // << lat_rad * SG_RADIANS_TO_DEGREES << endl;
+ Point3D geod( lon_rad, lat_rad, 0 );
+ Point3D tmp = sgGeodToCart( geod );
+ sgVec3 world_up;
+ sgSetVec3( world_up, tmp.x(), tmp.y(), tmp.z() );
+ SGTime t = SGTime( lon_rad, lat_rad, "", 0 );
+
+ double best_angle = 180.0;
+ time_t best_time = cur_time;
+
+ for ( time_t secs = cur_time; secs < cur_time + day_secs; secs += 300 ) {
+ t.update( lon_rad, lat_rad, secs, 0 );
+ double angle = sun_angle( t, world_up, lon_rad, lat_rad );
+ if ( angle < best_angle ) {
+ // cout << "best angle = " << angle << " offset = "
+ // << secs - cur_time << endl;
+ best_angle = angle;
+ best_time = secs;
+ }
+ }
+
+ if ( best_time > day_secs / 2 ) {
+ best_time -= day_secs;
+ }
+
+ return best_time - cur_time;
+}
+
+
+/**
+ * Given the current unix time in seconds, calculate seconds to midnight
+ */
+time_t fgTimeSecondsUntilMidnight( time_t cur_time,
+ double lon_rad,
+ double lat_rad )
+{
+ // cout << "location = " << lon_rad * SG_RADIANS_TO_DEGREES << ", "
+ // << lat_rad * SG_RADIANS_TO_DEGREES << endl;
+ Point3D geod( lon_rad, lat_rad, 0 );
+ Point3D tmp = sgGeodToCart( geod );
+ sgVec3 world_up;
+ sgSetVec3( world_up, tmp.x(), tmp.y(), tmp.z() );
+ SGTime t = SGTime( lon_rad, lat_rad, "", 0 );
+
+ double best_angle = 0.0;
+ time_t best_time = cur_time;
+
+ for ( time_t secs = cur_time; secs < cur_time + day_secs; secs += 300 ) {
+ t.update( lon_rad, lat_rad, secs, 0 );
+ double angle = sun_angle( t, world_up, lon_rad, lat_rad );
+ if ( angle > best_angle ) {
+ // cout << "best angle = " << angle << " offset = "
+ // << secs - cur_time << endl;
+ best_angle = angle;
+ best_time = secs;
+ }
+ }
+
+ if ( best_time > day_secs / 2 ) {
+ best_time -= day_secs;
+ }
+
+ return best_time - cur_time;
+}
+
+
+/**
+ * Given the current unix time in seconds, calculate seconds to dusk
+ */
+time_t fgTimeSecondsUntilDusk( time_t cur_time,
+ double lon_rad,
+ double lat_rad )
+{
+ // cout << "location = " << lon_rad * SG_RADIANS_TO_DEGREES << ", "
+ // << lat_rad * SG_RADIANS_TO_DEGREES << endl;
+ Point3D geod( lon_rad, lat_rad, 0 );
+ Point3D tmp = sgGeodToCart( geod );
+ sgVec3 world_up;
+ sgSetVec3( world_up, tmp.x(), tmp.y(), tmp.z() );
+ SGTime t = SGTime( lon_rad, lat_rad, "", 0 );
+
+ double best_diff = 90.0;
+ double last_angle = -99999.0;
+ time_t best_time = cur_time;
+
+ for ( time_t secs = cur_time; secs < cur_time + day_secs; secs += 300 ) {
+ t.update( lon_rad, lat_rad, secs, 0 );
+ double angle = sun_angle( t, world_up, lon_rad, lat_rad );
+ double diff = fabs( angle - 90.0 );
+ if ( diff < best_diff ) {
+ if ( last_angle <= 180.0 && ( last_angle < angle ) ) {
+ // cout << "best angle = " << angle << " offset = "
+ // << secs - cur_time << endl;
+ best_diff = diff;
+ best_time = secs;
+ }
+ }
+
+ last_angle = angle;
+ }
+
+ if ( best_time > day_secs / 2 ) {
+ best_time -= day_secs;
+ }
+
+ return best_time - cur_time;
+}
+
+
+/**
+ * Given the current unix time in seconds, calculate seconds to dawn
+ */
+time_t fgTimeSecondsUntilDawn( time_t cur_time,
+ double lon_rad,
+ double lat_rad )
+{
+ // cout << "location = " << lon_rad * SG_RADIANS_TO_DEGREES << ", "
+ // << lat_rad * SG_RADIANS_TO_DEGREES << endl;
+ Point3D geod( lon_rad, lat_rad, 0 );
+ Point3D tmp = sgGeodToCart( geod );
+ sgVec3 world_up;
+ sgSetVec3( world_up, tmp.x(), tmp.y(), tmp.z() );
+ SGTime t = SGTime( lon_rad, lat_rad, "", 0 );
+
+ double best_diff = 90.0;
+ double last_angle = -99999.0;
+ time_t best_time = cur_time;
+
+ for ( time_t secs = cur_time; secs < cur_time + day_secs; secs += 300 ) {
+ t.update( lon_rad, lat_rad, secs, 0 );
+ double angle = sun_angle( t, world_up, lon_rad, lat_rad );
+ double diff = fabs( angle - 90.0 );
+ if ( diff < best_diff ) {
+ if ( last_angle <= 180.0 && ( last_angle > angle ) ) {
+ // cout << "best angle = " << angle << " offset = "
+ // << secs - cur_time << endl;
+ best_diff = diff;
+ best_time = secs;
+ }
+ }
+
+ last_angle = angle;
+ }
+
+ if ( best_time > day_secs / 2 ) {
+ best_time -= day_secs;
+ }
+
+ return best_time - cur_time;
+}
--- /dev/null
+/*
+ * sunsolver.hxx - given a location on earth and a time of day/date,
+ * find the number of seconds to various sun positions.
+ *
+ * Written by Curtis Olson, started September 2003.
+ *
+ * Copyright (C) 2003 Curtis L. Olson - curt@flightgear.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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+
+#ifndef _SUNSOLVER_HXX
+#define _SUNSOLVER_HXX
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include <simgear/compiler.h>
+
+#ifdef SG_HAVE_STD_INCLUDES
+# include <ctime>
+#else
+# include <time.h>
+#endif
+
+/**
+ * Given the current unix time in seconds, calculate seconds to
+ * highest sun angle.
+ */
+time_t fgTimeSecondsUntilNoon( time_t cur_time,
+ double lon_rad,
+ double lat_rad );
+
+
+/**
+ * Given the current unix time in seconds, calculate seconds to lowest
+ * sun angle.
+ */
+time_t fgTimeSecondsUntilMidnight( time_t cur_time,
+ double lon_rad,
+ double lat_rad );
+
+/**
+ * Given the current unix time in seconds, calculate seconds to dusk
+ */
+time_t fgTimeSecondsUntilDusk( time_t cur_time,
+ double lon_rad,
+ double lat_rad );
+
+
+/**
+ * Given the current unix time in seconds, calculate seconds to dawn
+ */
+time_t fgTimeSecondsUntilDawn( time_t cur_time,
+ double lon_rad,
+ double lat_rad );
+
+
+
+#endif /* _SUNSOLVER_HXX */