From e689fe036616b02dbe8d7c9230aa20ab1eb781c1 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 24 May 2020 01:58:10 +0200 Subject: [PATCH] Sunrise and Sunset --- Moose Development/Moose/Core/Point.lua | 176 +++++++++++++++++++- Moose Development/Moose/Utilities/Utils.lua | 157 +++++++++++++---- 2 files changed, 298 insertions(+), 35 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index bc5018a7b..cc30b1fce 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1969,6 +1969,174 @@ do -- COORDINATE return InSphere end + --- Get sun rise time for a specific date at the coordinate. + -- @param #COORDINATE self + -- @param #number Day The day. + -- @param #number Month The month. + -- @param #number Year The year. + -- @param #boolean InSeconds If true, return the sun rise time in seconds. + -- @return #string Sunrise time, e.g. "05:41". + function COORDINATE:GetSunriseAtDate(Day, Month, Year, InSeconds) + + -- Day of the year. + local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) + + local Latitude, Longitude=self:GetLLDDM() + + local Tdiff=UTILS.GMTToLocalTimeDifference() + + local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) + + if InSeconds then + return sunrise + else + return UTILS.SecondsToClock(sunrise, true) + end + + end + + --- Get todays sun rise time. + -- @param #COORDINATE self + -- @param #boolean InSeconds If true, return the sun rise time in seconds. + -- @return #string Sunrise time, e.g. "05:41". + function COORDINATE:GetSunrise(InSeconds) + + -- Get current day of the year. + local DayOfYear=UTILS.GetMissionDayOfYear() + + -- Lat and long at this point. + local Latitude, Longitude=self:GetLLDDM() + + -- GMT time diff. + local Tdiff=UTILS.GMTToLocalTimeDifference() + + -- Sunrise in seconds of the day. + local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) + + -- Debug output. + --self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s + %d days (DayOfYear=%d): %s (GMT %d)", Latitude, Longitude, date, x, DayOfYear, UTILS.SecondsToClock(sunrise), Tdiff)) + + if InSeconds then + return sunrise + else + return UTILS.SecondsToClock(sunrise, true) + end + + end + + --- Get minutes until the next sun rise at this coordinate. + -- @param #COORDINATE self + -- @param OnlyToday If true, only calculate the sun rise of today. If sun has already risen, the time in negative minutes since sunrise is reported. + -- @return #number Minutes to the next sunrise. + function COORDINATE:GetMinutesToSunrise(OnlyToday) + + -- Seconds of today + local time=UTILS.SecondsOfToday() + + -- Next Sunrise in seconds. + local sunrise=nil + + -- Time to sunrise. + local delta=nil + + if OnlyToday then + + --- + -- Sunrise of today + --- + + sunrise=self:GetSunrise(true) + + delta=sunrise-time + + else + + --- + -- Sunrise of tomorrow + --- + + -- Tomorrows day of the year. + local DayOfYear=UTILS.GetMissionDayOfYear()+1 + + local Latitude, Longitude=self:GetLLDDM() + + local Tdiff=UTILS.GMTToLocalTimeDifference() + + sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) + + delta=sunrise+UTILS.SecondsToMidnight() + + end + + return delta/60 + end + + --- Check if it is day, i.e. if the sun has risen about the horizon at this coordinate. + -- @param #COORDINATE self + -- @return #boolean If true, it is day. If false, it is night time. + function COORDINATE:IsDay() + + -- Todays sun rise in sec. + local sunrise=self:GetSunrise(true) + + -- Todays sun set in sec. + local sunset=self:GetSunset(true) + + local time=timer.getAbsTime() + local clock=UTILS.SecondsToClock(time, true) + time=UTILS.ClockToSeconds(clock) + + if time>sunrise and time<=sunset then + return true + else + return false + end + + end + + --- Check if it is night, i.e. if the sun has set below the horizon at this coordinate. + -- @param #COORDINATE self + -- @return #boolean If true, it is night. If false, it is day time. + function COORDINATE:IsNight() + return not self:IsDay() + end + + --- Get todays sun set time. + -- @param #COORDINATE self + -- @param #boolean InSeconds If true, return the sun set time in seconds. + -- @return #string Sunrise time, e.g. "20:41". + function COORDINATE:GetSunset(InSeconds) + + -- Mission start date + local date, Year, Month, Day=UTILS.GetDCSMissionDate() + + -- Day of the year. + local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) + + -- Get the number of days that passed since mission start. + local time=timer.getAbsTime() + local clock=UTILS.SecondsToClock(time, false) + local x=tonumber(UTILS.Split(clock, "+")[2]) + + DayOfYear=DayOfYear+x + + local Latitude, Longitude=self:GetLLDDM() + + local Tdiff=UTILS.GMTToLocalTimeDifference() + + local sunset=UTILS.GetSunRiseAndSet(DayOfYear,Latitude,Longitude, false, Tdiff) + + -- Debug output. + self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s+%dd (DayOfYear=%d): %s", Latitude, Longitude, date, x, DayOfYear, UTILS.SecondsToClock(sunset))) + + if InSeconds then + return sunset + else + return UTILS.SecondsToClock(sunset, true) + end + + end + --- Return a BR string from a COORDINATE to the COORDINATE. -- @param #COORDINATE self @@ -2036,11 +2204,11 @@ do -- COORDINATE return "" end - --- Get Latitude and Longitude in Degree Minute Second. + --- Get Latitude and Longitude in Degrees Decimal Minutes (DDM). -- @param #COORDINATE self - -- @return #number Latitude. - -- @return #number Lontitude. - function COORDINATE:GetLLDMS() + -- @return #number Latitude in DDM. + -- @return #number Lontitude in DDM. + function COORDINATE:GetLLDDM() return coord.LOtoLL( self:GetVec3() ) end diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 3fc5b3f27..17ffd6b5d 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -718,7 +718,8 @@ function UTILS.SecondsToClock(seconds, short) local clock=hours..":"..mins..":"..secs.."+"..days if short then if hours=="00" then - clock=mins..":"..secs + --clock=mins..":"..secs + clock=hours..":"..mins..":"..secs else clock=hours..":"..mins..":"..secs end @@ -727,6 +728,26 @@ function UTILS.SecondsToClock(seconds, short) end end +--- Seconds of today. +-- @return #number Seconds passed since last midnight. +function UTILS.SecondsOfToday() + + -- Time in seconds. + local time=timer.getAbsTime() + + -- Short format without days since mission start. + local clock=UTILS.SecondsToClock(time, true) + + -- Time is now the seconds passed since last midnight. + return UTILS.ClockToSeconds(clock) +end + +--- Cound seconds until next midnight. +-- @return #number Seconds to midnight. +function UTILS.SecondsToMidnight() + return 24*60*60-UTILS.SecondsOfToday() +end + --- Convert clock time from hours, minutes and seconds to seconds. -- @param #string clock String of clock time. E.g., "06:12:35" or "5:1:30+1". Format is (H)H:(M)M:((S)S)(+D) H=Hours, M=Minutes, S=Seconds, D=Days. -- @return #number Seconds. Corresponds to what you cet from timer.getAbsTime() function. @@ -1002,7 +1023,7 @@ function UTILS.GetDCSMap() return env.mission.theatre end ---- Returns the mission date. This is the date the mission started. +--- Returns the mission date. This is the date the mission **started**. -- @return #string Mission date in yyyy/mm/dd format. -- @return #number The year anno domini. -- @return #number The month. @@ -1011,9 +1032,53 @@ function UTILS.GetDCSMissionDate() local year=tostring(env.mission.date.Year) local month=tostring(env.mission.date.Month) local day=tostring(env.mission.date.Day) - return string.format("%s/%s/%s", year, month, day), year, month, day + return string.format("%s/%s/%s", year, month, day), tonumber(year), tonumber(month), tonumber(day) end +--- Returns the day of the mission. +-- @return #number Day of the mission. Mission starts on day 0. +function UTILS.GetMissionDay() + + local time=timer.getAbsTime() + + local clock=UTILS.SecondsToClock(time, false) + + local x=tonumber(UTILS.Split(clock, "+")[2]) + + return x +end + +--- Returns the current day of the year of the mission. +-- @return #number Current day of year of the mission. For example, January 1st returns 0, January 2nd returns 1 etc. +function UTILS.GetMissionDayOfYear() + + local Date, Year, Month, Day=UTILS.GetDCSMissionDate() + + local d=UTILS.GetMissionDay() + + return UTILS.GetDayOfYear(Year, Month, Day)+d + +end + +--- Returns the current date. +-- @return #string Mission date in yyyy/mm/dd format. +-- @return #number The year anno domini. +-- @return #number The month. +-- @return #number The day. +function UTILS.GetDate() + + -- Mission start date + local date, year, month, day=UTILS.GetDCSMissionDate() + + local time=timer.getAbsTime() + + local clock=UTILS.SecondsToClock(time, false) + + local x=tonumber(UTILS.Split(clock, "+")[2]) + + local day=day+x + +end --- Returns the magnetic declination of the map. -- Returned values for the current maps are: @@ -1148,30 +1213,63 @@ function UTILS.GetCallsignName(Callsign) return "Ghostrider" end +--- Get the time difference between GMT and local time. +-- @return #number Local time difference in hours compared to GMT. E.g. Dubai is GMT+4 ==> +4 is returned. +function UTILS.GMTToLocalTimeDifference() + + local theatre=UTILS.GetDCSMap() + + if theatre==DCSMAP.Caucasus then + return 4 -- Caucasus UTC+4 hours + elseif theatre==DCSMAP.PersianGulf then + return 4 -- Abu Dhabi UTC+4 hours + elseif theatre==DCSMAP.NTTR then + return -7 -- Las Vegas UTC-7 hours + elseif theatre==DCSMAP.Normandy then + return 1 -- Calais UTC+1 hour + else + BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre))) + return 0 + end + +end + + +--- Get the day of the year. Counting starts on 1st of January. +-- @param #number Year The year. +-- @param #number Month The month. +-- @param #number Day The day. +-- @return #number The day of the year. +function UTILS.GetDayOfYear(Year, Month, Day) + + local floor = math.floor + + local n1 = floor(275 * Month / 9) + local n2 = floor((Month + 9) / 12) + local n3 = (1 + floor((Year - 4 * floor(Year / 4) + 2) / 3)) + + return n1 - (n2 * n3) + Day - 30 +end --- Get sunrise or sun set of a specific day of the year at a specific location. --- @param #number Day Day of the year. --- @param #number Month Month of the year. --- @param #number Year Year. +-- @param #number DayOfYear The day of the year. -- @param #number Latitude Latitude. -- @param #number Longitude Longitude. -- @param #boolean Rising If true, calc sun rise, or sun set otherwise. +-- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. -- @return #number Sun rise/set in seconds of the day. -function UTILS.GetSunRiseAndSet(Day, Month, Year, Latitude, Longitude, Rising) +function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) - local date={} - date.day=Day - date.month=Month - date.year=Year - + -- Defaults local zenith=90.83 local latitude=Latitude local longitude=Longitude local rising=Rising + local n=DayOfYear + Tlocal=Tlocal or 0 - local current_time = nil - local srs_args + -- Short cuts. local rad = math.rad local deg = math.deg local floor = math.floor @@ -1196,15 +1294,6 @@ function UTILS.GetSunRiseAndSet(Day, Month, Year, Latitude, Longitude, Rising) return val end end - - local function day_of_year(date) - local n1 = floor(275 * date.month / 9) - local n2 = floor((date.month + 9) / 12) - local n3 = (1 + floor((date.year - 4 * floor(date.year / 4) + 2) / 3)) - return n1 - (n2 * n3) + date.day - 30 - end - - local n = day_of_year(date) -- Convert the longitude to hour value and calculate an approximate time local lng_hour = longitude / 15 @@ -1257,13 +1346,11 @@ function UTILS.GetSunRiseAndSet(Day, Month, Year, Latitude, Longitude, Rising) -- Calculate local mean time of rising/setting local T = H + RA - (0.06571 * t) - 6.622 - - print(T) - + -- Adjust back to UTC local UT = fit_into_range(T - lng_hour, 0, 24) - return floor(UT)*60*60+frac(UT)*60*60 + return floor(UT)*60*60+frac(UT)*60*60+Tlocal*60*60 end --- Get sun rise of a specific day of the year at a specific location. @@ -1273,9 +1360,13 @@ function UTILS.GetSunRiseAndSet(Day, Month, Year, Latitude, Longitude, Rising) -- @param #number Latitude Latitude. -- @param #number Longitude Longitude. -- @param #boolean Rising If true, calc sun rise, or sun set otherwise. +-- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. Default 0. -- @return #number Sun rise in seconds of the day. -function UTILS.GetSunrise(Day, Month, Year, Latitude, Longitude) - return UTILS.GetSunRiseAndSet(Day, Month, Year, Latitude, Longitude, true) +function UTILS.GetSunrise(Day, Month, Year, Latitude, Longitude, Tlocal) + + local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) + + return UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tlocal) end --- Get sun set of a specific day of the year at a specific location. @@ -1285,7 +1376,11 @@ end -- @param #number Latitude Latitude. -- @param #number Longitude Longitude. -- @param #boolean Rising If true, calc sun rise, or sun set otherwise. +-- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. Default 0. -- @return #number Sun rise in seconds of the day. -function UTILS.GetSunset(Day, Month, Year, Latitude, Longitude) - return UTILS.GetSunRiseAndSet(Day, Month, Year, Latitude, Longitude, false) +function UTILS.GetSunset(Day, Month, Year, Latitude, Longitude, Tlocal) + + local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day) + + return UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tlocal) end \ No newline at end of file