⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 solartimer.cpp

📁 Powerful and Portable GPS application -- support Linux, Windows, Windows CE GPS navigation and Map m
💻 CPP
字号:
/* *  Roadnav *  SolarTimer.cpp * *  Copyright (c) 2004 - 2007 Richard L. Lynch <rllynch@users.sourceforge.net> * *  This program is free software; you can redistribute it and/or *  modify it under the terms of version 2 of the GNU General Public License *  as published by the Free Software Foundation. * *  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */    ///////////////////////////////////////////////////////////////////////////////// \file////// Solar Timer - A class that fires events at sunrise and sunset/////////////////////////////////////////////////////////////////////////////////  #ifdef HAVE_CONFIG_H#  include <config.h>#endif  #ifdef _MSC_VER#pragma warning(disable: 4786)#pragma warning(disable: 4800)#endif  #ifdef HAVE_MATH_H#include <math.h>#endif#include <wx/wx.h>  #include "SolarTimer.h"#include "libroadnav/MapSupport.h"#include "libroadnav/UnitConversion.h"template <class T>void ForceInRange(const T& min,T& value,const T& max){   if ( value < min )      value += max;   else if ( max <= value )      value -= max;}  #define TIMERID 1000  IMPLEMENT_DYNAMIC_CLASS(SolarEvent, wxEvent) DEFINE_EVENT_TYPE(wxEVT_SOLAR) IMPLEMENT_DYNAMIC_CLASS(wxTimeChangeEvent,wxEvent)DEFINE_EVENT_TYPE(wxEVT_TIMECHANGE) //////////////////////////////////////////////////////////////////////////////////// SolarTimer event table/////////////////////////////////////////////////////////////////////////////////BEGIN_EVENT_TABLE(SolarTimer, wxEvtHandler) 	EVT_TIMER(TIMERID, SolarTimer::OnTimer) 	EVT_TIMECHANGE(SolarTimer::OnTimeChange)END_EVENT_TABLE()  //////////////////////////////////////////////////////////////////////////////////// Constructor////////////////////////////////////////////////////////////////////////////////SolarTimer::SolarTimer() {	Init();} //////////////////////////////////////////////////////////////////////////////////// Constructor////////////////////////////////////////////////////////////////////////////////SolarTimer::SolarTimer(	wxEvtHandler * owner, 						double fLong, double fLat,						EventType type) {	Init();	SetOwner(owner, fLong, fLat, type);}  //////////////////////////////////////////////////////////////////////////////////// Constructor////////////////////////////////////////////////////////////////////////////////void SolarTimer::SetOwner(wxEvtHandler * owner, 						  double fLong, double fLat,					      EventType type) {	m_pOwner = owner;	m_EventType = type;	SetPosition(fLong, fLat);}  //////////////////////////////////////////////////////////////////////////////////// Sets the position for which sunrise/sunset events are to occur////////////////////////////////////////////////////////////////////////////////void SolarTimer::SetPosition(double fLong, double fLat) {	if (m_fLong != fLong || m_fLat != fLat)    {    	m_fLong = fLong;		m_fLat = fLat;      		ComputeSunriset();		NotifyIfNeeded();	}} //////////////////////////////////////////////////////////////////////////////////// Starts the solar timer////////////////////////////////////////////////////////////////////////////////void SolarTimer::Start() {	if (!m_Timer.IsRunning())	{		// start a one time timer that will get us to 		// the next whole minute		wxDateTime now = wxDateTime::Now();		int sec = now.GetSecond();		NotifyIfNeeded();		m_Timer.Start((60 - sec) * 1000, true);	}}  //////////////////////////////////////////////////////////////////////////////////// Stops the solar timer////////////////////////////////////////////////////////////////////////////////void SolarTimer::Stop() {	m_Timer.Stop();}  //////////////////////////////////////////////////////////////////////////////////// Returns true if it is daytime////////////////////////////////////////////////////////////////////////////////bool SolarTimer::IsDaytime() {	wxDateTime now = wxDateTime::Now();	if (!Valid())		return true;	return (m_Sunrise <= now && now < m_Sunset ? true : false);} //////////////////////////////////////////////////////////////////////////////////// Returns the coordinates for which sunrise/sunset are computed////////////////////////////////////////////////////////////////////////////////void SolarTimer::GetPosition(double &fLong, double &fLat) const{	fLong = m_fLong;    fLat = m_fLat;     }  //////////////////////////////////////////////////////////////////////////////////// Returns the type of solar event////////////////////////////////////////////////////////////////////////////////SolarTimer::EventType SolarTimer::GetEventType() const{	return m_EventType;}//////////////////////////////////////////////////////////////////////////////////// Returns the sunrise time, adjusted for DST as necessary, for the/// current position.////////////////////////////////////////////////////////////////////////////////wxDateTime SolarTimer::GetSunrise() const{	return m_Sunrise;}//////////////////////////////////////////////////////////////////////////////////// Returns the sunset time, adjusted for DST as necessary, for the/// current position.////////////////////////////////////////////////////////////////////////////////wxDateTime SolarTimer::GetSunset() const{	return m_Sunset;}//////////////////////////////////////////////////////////////////////////////////// Virtual function called at sunrise and sunset. Subclasses should/// override this method.////////////////////////////////////////////////////////////////////////////////void SolarTimer::Notify() {	if (!m_pOwner)		return;			// Time for an event....    SolarEvent event(m_bIsDaytime);  	event.SetEventObject(this);  	m_pOwner->AddPendingEvent(event);} void SolarTimer::OnTimer(wxTimerEvent & event) {	if (m_Timer.IsOneShot())    {		// Keep timer running on 1 minute interval		m_Timer.Start(60000);	}		NotifyIfNeeded();}void SolarTimer::NotifyIfNeeded(){	bool bIsDaytime = IsDaytime();		if (m_bIsDaytime != bIsDaytime)    {		m_bIsDaytime = bIsDaytime;		Notify();	}	if (IsNewDay())    {		m_Today = wxDateTime::Today();		ComputeSunriset();	}}void SolarTimer::OnTimeChange(wxTimeChangeEvent& event){   // The clock got changed... stop the timer and restart it   Stop();   Start();}bool SolarTimer::IsNewDay() {	wxDateTime today = wxDateTime::Today();	return today != m_Today;}      void SolarTimer::Init() {	m_pOwner = NULL;	m_fLong = 0;	m_fLat = 0;	m_Timer.SetOwner(this, TIMERID);	m_EventType = Official;	m_Today = wxDateTime::Today();	SetOwner(this, 0, 0, m_EventType);	m_bIsDaytime = IsDaytime();	Start();} void SolarTimer::ComputeSunriset() {	wxDateTime now = wxDateTime::Now();	int year = now.GetYear();	int month = now.GetMonth() + 1;  	wxDateTime::wxDateTime_t day = now.GetDay();  	double zenith = 90.833333333;  	switch (m_EventType)    {	case Official:		zenith = 90.833333333;	break;    	case Civil:    	zenith = 96.;	break;    	case Nautical:    	zenith = 102.;	break;    	case Astronomical:    	zenith = 108.;	break;	}  	// Compute day of year	int N1 = (int) (floor((double) 275 * month / 9));	int N2 = (int) (floor((double) (month + 9) / 12));	int N3 = (int) (1 + floor((double) (year - 4 * floor((double) year / 4) + 2) / 3));  	int N = N1 - (N2 * N3) + day - 30;  		// Convert the m_fLong to hour value and calculate an approximate time	double lngHour = m_fLong / 15.;  	double t_rise = N + (( 6 - lngHour) / 24);	double t_set  = N + ((18 - lngHour) / 24);  	// Calculate the Sun's mean anomaly	double M_rise = (0.9856 * t_rise) - 3.289;	double M_set  = (0.9856 * t_set)  - 3.289;  	// Calculate the Sun's true longitude	double L_rise = M_rise + (1.916 * sin(DegreesToRadians(M_rise))) +    	(0.020 * sin(DegreesToRadians(2 * M_rise))) + 282.634;  	double L_set = M_set + (1.916 * sin(DegreesToRadians(M_set))) +    	(0.020 * sin(DegreesToRadians(2 * M_set))) + 282.634;   ForceInRange(0.,L_rise,360.);   ForceInRange(0.,L_set, 360.);  	// Calculate the Sun's right ascension	double RA_rise = RadiansToDegrees(atan(0.91764 * tan(DegreesToRadians(L_rise))));	double RA_set  = RadiansToDegrees(atan(0.91764 * tan(DegreesToRadians(L_set))));	// Right ascension value needs to be in the same quadrant as L	double Lquad_rise = (floor(L_rise / 90)) * 90;	double Lquad_set  = (floor(L_set  / 90)) * 90;  	double RAquad_rise = (floor(RA_rise / 90)) * 90;	double RAquad_set  = (floor(RA_set  / 90)) * 90;  	RA_rise += Lquad_rise - RAquad_rise;	RA_set  += Lquad_set  - RAquad_set;      // Right ascension value needs to be convered into hours   RA_rise /= 15.;   RA_set  /= 15.;  	// Calculate the Sun's declination	double sinDec_rise = 0.39782 * sin(DegreesToRadians(L_rise));	double cosDec_rise = cos(asin(sinDec_rise));  	double sinDec_set = 0.39782 * sin(DegreesToRadians(L_set));	double cosDec_set = cos(asin(sinDec_set));	// Calculate the Sun's local hour angle	double cosH_rise = (cos(DegreesToRadians(zenith)) 					 - sinDec_rise * sin(DegreesToRadians(m_fLat))) 					 /(cosDec_rise * cos(DegreesToRadians(m_fLat)));  	double cosH_set = (cos(DegreesToRadians(zenith))					- sinDec_set * sin(DegreesToRadians(m_fLat))) 					/(cosDec_set * cos(DegreesToRadians(m_fLat)));  	// Finish calcuating H and convert into hours	double H_rise = 360 - RadiansToDegrees(acos(cosH_rise));	double H_set  = RadiansToDegrees(acos(cosH_set));  	H_rise /= 15.;	H_set  /= 15.;  	// Calculate local mean time of rising/settings	double T_rise = H_rise + RA_rise - (0.06571 * t_rise) - 6.622;	double T_set  = H_set  + RA_set  - (0.06571 * t_set)  - 6.622;  	// Adjust back to UTC	double UT_rise = T_rise - lngHour;	double UT_set  = T_set  - lngHour;	// Adjust to 24 hours   ForceInRange(0.,UT_rise,24.);   ForceInRange(0.,UT_set, 24.);     // Determine the local hour offset based on the computer clock.   // UT_rise/UT_set are the sunrise/set times in universal   // time at the present location. These times need to be convered to local time,   // as determined by the computer's settings, (not the actual local time).   //   // Sunrise/set need to be computed for the present location, for the time zone the   // computer is set to regardless of the actual time zone the computer is in. Assume you    // arrive in New York City from Los Angeles and your computer is still set to Pacific   // time. Sunset is 11:00PM UT, which is 6:00PM EST. Since your computer is still   // on Pacific time, the sunset event needs to fire when the computer's clock hits 4:00PM PST   //   // ToGMT accounts for daylight savings time#if wxCHECK_VERSION(2, 6, 2)	long local_offset = (wxDateTime::Now() - wxDateTime::Now().ToUTC()).GetHours();#else	long local_offset = (wxDateTime::Now().ToGMT() - wxDateTime::Now()).GetHours();#endif	double LT_rise = UT_rise + local_offset;  	double LT_set  = UT_set  + local_offset;  	// Adjust to 24 hours   ForceInRange(0.,LT_rise,24.);   ForceInRange(0.,LT_set, 24.);  	int h = (int) floor(LT_rise);	double m = 60 * (LT_rise - h);	double s = floor(60 * (m - floor(m)));	m = floor(m);	m_Sunrise.Set((int) h, (int) m, (int) s, 0);  	h = (int) floor(LT_set);	m = 60 * (LT_set - h);	s = floor(60 * (m - floor(m)));	m = floor(m);	m_Sunset.Set((int) h, (int) m, (int) s, 0);}bool SolarTimer::Valid(){	if (fabs(m_fLong) < 0.01 && fabs(m_fLat) < 0.01)		return false;			if (!m_Sunrise.IsValid())		return false;	if (!m_Sunset.IsValid())		return false;	return true;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -