mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-24 00:47:57 -05:00
[FEATURE] Introduces mesh virtual datasets With the mesh calculator the user can choose to create those "virtual" dataset groups that will be added to the layer. Then, for these dataset groups, values are not stored in memory but each dataset is calculated when needed whit the formula entered in the mesh calculator. Those virtual dataset groups are saved with the project. If needed, the user can remove them or can persist them on files to make them persistent. Co-authored-by: Étienne Trimaille <gustrimaille@yahoo.fr>
400 lines
12 KiB
C++
400 lines
12 KiB
C++
/*
|
|
MDAL - Mesh Data Abstraction Library (MIT License)
|
|
Copyright (C) 2019 Vincent Cloarec (vcloarec at gmail dot com)
|
|
*/
|
|
#include "mdal_datetime.hpp"
|
|
#include "mdal_utils.hpp"
|
|
|
|
|
|
constexpr double MILLISECONDS_IN_SECOND = 1000;
|
|
constexpr double MILLISECONDS_IN_MINUTE = 1000 * 60;
|
|
constexpr double MILLISECONDS_IN_HOUR = 1000 * 60 * 60;
|
|
constexpr double MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24;
|
|
constexpr double MILLISECONDS_IN_WEEK = 1000 * 60 * 60 * 24 * 7;
|
|
|
|
//https://www.unidata.ucar.edu/software/netcdf-java/current/CDM/CalendarDateTime.html
|
|
constexpr double MILLISECONDS_IN_EXACT_YEAR = 3.15569259747e10; //CF Compliant
|
|
constexpr double MILLISECONDS_IN_MONTH_CF = MILLISECONDS_IN_EXACT_YEAR / 12.0; //CF Compliant
|
|
|
|
MDAL::DateTime::DateTime() = default;
|
|
|
|
MDAL::DateTime::DateTime( int year, int month, int day, int hours, int minutes, double seconds, MDAL::DateTime::Calendar calendar )
|
|
{
|
|
DateTimeValues value{year, month, day, hours, minutes, seconds};
|
|
|
|
switch ( calendar )
|
|
{
|
|
case MDAL::DateTime::Gregorian:
|
|
setWithGregorianJulianCalendarDate( value );
|
|
break;
|
|
case MDAL::DateTime::ProlepticGregorian:
|
|
setWithGregorianCalendarDate( value );
|
|
break;
|
|
case MDAL::DateTime::Julian:
|
|
setWithJulianCalendarDate( value );
|
|
break;
|
|
}
|
|
}
|
|
|
|
MDAL::DateTime::DateTime( double value, Epoch epoch ): mValid( true )
|
|
{
|
|
switch ( epoch )
|
|
{
|
|
case MDAL::DateTime::Unix:
|
|
mJulianTime = ( DateTime( 1970, 01, 01, 0, 0, 0, Gregorian ) + RelativeTimestamp( value, RelativeTimestamp::seconds ) ).mJulianTime;
|
|
break;
|
|
case MDAL::DateTime::JulianDay:
|
|
mJulianTime = int64_t( value * MILLISECONDS_IN_DAY + 0.5 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
MDAL::DateTime::DateTime( const std::string &fromISO8601 )
|
|
{
|
|
std::vector<std::string> splitedDateTime = split( fromISO8601, 'T' );
|
|
|
|
if ( splitedDateTime.size() != 2 )
|
|
return;
|
|
//parse date
|
|
std::vector<std::string> splitedDate = split( splitedDateTime.at( 0 ), '-' );
|
|
if ( splitedDate.size() != 3 )
|
|
return;
|
|
|
|
//parse time
|
|
splitedDateTime[1] = replace( splitedDateTime.at( 1 ), "Z", "", ContainsBehaviour::CaseInsensitive );
|
|
std::vector<std::string> splitedTime = split( splitedDateTime.at( 1 ), ':' );
|
|
if ( splitedTime.size() < 2 || splitedTime.size() > 3 )
|
|
return;
|
|
|
|
DateTimeValues dateTimeValues;
|
|
dateTimeValues.year = toInt( splitedDate[0] );
|
|
dateTimeValues.month = toInt( splitedDate[1] );
|
|
dateTimeValues.day = toInt( splitedDate[2] );
|
|
dateTimeValues.hours = toInt( splitedTime[0] );
|
|
dateTimeValues.minutes = toInt( splitedTime[1] );
|
|
if ( splitedTime.size() == 3 )
|
|
dateTimeValues.seconds = toDouble( splitedTime[2] );
|
|
else
|
|
dateTimeValues.seconds = 0.0;
|
|
|
|
setWithGregorianCalendarDate( dateTimeValues );
|
|
}
|
|
|
|
std::string MDAL::DateTime::toStandardCalendarISO8601() const
|
|
{
|
|
if ( mValid )
|
|
{
|
|
DateTimeValues value = dateTimeGregorianProleptic();
|
|
if ( value.year > 0 )
|
|
return toString( value );
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
double MDAL::DateTime::toJulianDay() const
|
|
{
|
|
return mJulianTime / MILLISECONDS_IN_DAY;
|
|
}
|
|
|
|
std::string MDAL::DateTime::toJulianDayString() const
|
|
{
|
|
return std::to_string( toJulianDay() );
|
|
}
|
|
|
|
std::vector<int> MDAL::DateTime::expandToCalendarArray() const
|
|
{
|
|
std::vector<int> dateTimeArray( 6, 0 );
|
|
if ( mValid )
|
|
{
|
|
DateTimeValues value = dateTimeGregorianProleptic();
|
|
dateTimeArray[0] = value.year;
|
|
dateTimeArray[1] = value.month;
|
|
dateTimeArray[2] = value.day;
|
|
dateTimeArray[3] = value.hours;
|
|
dateTimeArray[4] = value.minutes;
|
|
dateTimeArray[5] = int( value.seconds + 0.5 );
|
|
}
|
|
|
|
return dateTimeArray;
|
|
}
|
|
|
|
|
|
MDAL::DateTime MDAL::DateTime::operator+( const MDAL::RelativeTimestamp &duration ) const
|
|
{
|
|
if ( !mValid )
|
|
return DateTime();
|
|
return DateTime( mJulianTime + duration.mDuration );
|
|
}
|
|
|
|
|
|
MDAL::DateTime MDAL::DateTime::operator-( const MDAL::RelativeTimestamp &duration ) const
|
|
{
|
|
if ( !mValid )
|
|
return DateTime();
|
|
return DateTime( mJulianTime - duration.mDuration );
|
|
}
|
|
|
|
bool MDAL::DateTime::operator==( const MDAL::DateTime &other ) const
|
|
{
|
|
if ( !mValid && !other.mValid )
|
|
return true;
|
|
|
|
return ( mValid && other.mValid ) && ( mJulianTime == other.mJulianTime );
|
|
}
|
|
|
|
bool MDAL::DateTime::operator<( const MDAL::DateTime &other ) const
|
|
{
|
|
if ( !mValid && !other.mValid )
|
|
return false;
|
|
return ( mValid && other.mValid ) && ( mJulianTime < other.mJulianTime );
|
|
}
|
|
|
|
bool MDAL::DateTime::isValid() const { return mValid; }
|
|
|
|
MDAL::DateTime::DateTime( int64_t julianTime ): mJulianTime( julianTime ), mValid( true )
|
|
{}
|
|
|
|
/*
|
|
MDAL::DateTime::DateTimeValues MDAL::DateTime::dateTimeGregorianJulianCalendar() const
|
|
{
|
|
// https://fr.wikipedia.org/wiki/Jour_julien
|
|
DateTimeValues values;
|
|
int Z = int( mJulianTime / MILLISECONDS_IN_DAY + 0.5 ); // integer part of julian days count
|
|
double F = ( mJulianTime - MILLISECONDS_IN_DAY * ( Z - 0.5 ) ) / MILLISECONDS_IN_DAY; // fractional part of julian days count;
|
|
int S;
|
|
|
|
if ( Z < 2299161 )
|
|
S = Z;
|
|
else
|
|
{
|
|
int alpha = int( ( Z - 1867216.25 ) / 36524.25 );
|
|
S = Z + 1 + alpha - int( alpha / 4 );
|
|
}
|
|
|
|
int B = S + 1524;
|
|
int C = int( ( B - 122.1 ) / 365.25 );
|
|
int D = int( 365.25 * C );
|
|
int E = int( ( B - D ) / 30.6001 );
|
|
|
|
values.day = B - D - int( 30.6001 * E );
|
|
if ( E < 14 )
|
|
values.month = E - 1;
|
|
else
|
|
values.month = E - 13;
|
|
|
|
if ( values.month > 2 )
|
|
values.year = C - 4716;
|
|
else
|
|
values.year = C - 4715;
|
|
|
|
values.hours = int( F / MILLISECONDS_IN_HOUR );
|
|
F = int( F - values.hours * MILLISECONDS_IN_HOUR );
|
|
values.minutes = int( F / MILLISECONDS_IN_MINUTE );
|
|
F = int( F - values.minutes * MILLISECONDS_IN_MINUTE );
|
|
values.seconds = int( F / MILLISECONDS_IN_SECOND );
|
|
|
|
return values;
|
|
}
|
|
*/
|
|
|
|
MDAL::DateTime::DateTimeValues MDAL::DateTime::dateTimeGregorianProleptic() const
|
|
{
|
|
// https://fr.wikipedia.org/wiki/Jour_julien
|
|
DateTimeValues values;
|
|
int Z = int( mJulianTime / MILLISECONDS_IN_DAY + 0.5 ); // integer part of julian days count
|
|
int F = int( mJulianTime - MILLISECONDS_IN_DAY * ( Z - 0.5 ) ) ; // fractional part of julian days count in ms;
|
|
|
|
int alpha = int( ( Z - 1867216.25 ) / 36524.25 );
|
|
int S = Z + 1 + alpha - int( alpha / 4 );
|
|
|
|
int B = S + 1524;
|
|
int C = int( ( B - 122.1 ) / 365.25 );
|
|
int D = int( 365.25 * C );
|
|
int E = int( ( B - D ) / 30.6001 );
|
|
|
|
values.day = B - D - int( 30.6001 * E );
|
|
if ( E < 14 )
|
|
values.month = E - 1;
|
|
else
|
|
values.month = E - 13;
|
|
|
|
if ( values.month > 2 )
|
|
values.year = C - 4716;
|
|
else
|
|
values.year = C - 4715;
|
|
|
|
values.hours = int( F / MILLISECONDS_IN_HOUR );
|
|
F = int( F - values.hours * MILLISECONDS_IN_HOUR );
|
|
values.minutes = int( F / MILLISECONDS_IN_MINUTE );
|
|
F = int( F - values.minutes * MILLISECONDS_IN_MINUTE );
|
|
values.seconds = int( F / MILLISECONDS_IN_SECOND );
|
|
|
|
return values;
|
|
}
|
|
|
|
|
|
void MDAL::DateTime::setWithGregorianCalendarDate( MDAL::DateTime::DateTimeValues values )
|
|
{
|
|
// https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
|
|
if ( values.month <= 2 )
|
|
{
|
|
values.year--;
|
|
values.month += 12;
|
|
}
|
|
|
|
int A = values.year / 100;
|
|
int B = A / 4;
|
|
int C = 2 - A + B;
|
|
int E = int( 365.25 * ( values.year + 4716 ) );
|
|
int F = int( 30.6001 * ( values.month + 1 ) );
|
|
double julianDay = C + values.day + E + F - 1524.5;
|
|
|
|
mValid = true;
|
|
mJulianTime = int64_t( julianDay * MILLISECONDS_IN_DAY +
|
|
( values.hours ) * MILLISECONDS_IN_HOUR +
|
|
values.minutes * MILLISECONDS_IN_MINUTE +
|
|
values.seconds * MILLISECONDS_IN_SECOND );
|
|
}
|
|
|
|
void MDAL::DateTime::setWithJulianCalendarDate( MDAL::DateTime::DateTimeValues values )
|
|
{
|
|
// https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
|
|
if ( values.month <= 2 )
|
|
{
|
|
values.year--;
|
|
values.month += 12;
|
|
}
|
|
|
|
int E = int( 365.25 * ( values.year + 4716 ) );
|
|
int F = int( 30.6001 * ( values.month + 1 ) );
|
|
double julianDay = values.day + E + F - 1524.5;
|
|
|
|
mValid = true;
|
|
mJulianTime = int64_t( julianDay * MILLISECONDS_IN_DAY +
|
|
( values.hours ) * MILLISECONDS_IN_HOUR +
|
|
values.minutes * MILLISECONDS_IN_MINUTE +
|
|
values.seconds * MILLISECONDS_IN_SECOND );
|
|
}
|
|
|
|
void MDAL::DateTime::setWithGregorianJulianCalendarDate( MDAL::DateTime::DateTimeValues values )
|
|
{
|
|
// https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
|
|
|
|
mValid = true;
|
|
|
|
if ( values.year > 1582 ||
|
|
( values.year == 1582 && ( values.month > 10 || ( values.month == 10 && values.day >= 15 ) ) ) ) // gregorian calendar
|
|
{
|
|
setWithGregorianCalendarDate( values );
|
|
}
|
|
else
|
|
setWithJulianCalendarDate( values );
|
|
}
|
|
|
|
std::string MDAL::DateTime::toString( MDAL::DateTime::DateTimeValues values ) const
|
|
{
|
|
int milliseconds = int( ( values.seconds - int( values.seconds ) ) * 1000 + 0.5 );
|
|
std::string msStr;
|
|
if ( milliseconds > 0 )
|
|
{
|
|
if ( milliseconds < 10 )
|
|
msStr = prependZero( std::to_string( milliseconds ), 3 );
|
|
else if ( milliseconds < 100 )
|
|
msStr = prependZero( std::to_string( milliseconds ), 2 );
|
|
else if ( milliseconds < 1000 )
|
|
msStr = std::to_string( milliseconds );
|
|
|
|
msStr = std::string( "," ).append( msStr );
|
|
}
|
|
|
|
std::string strDateTime = prependZero( std::to_string( values.year ), 4 ) + "-" +
|
|
prependZero( std::to_string( values.month ), 2 ) + "-" +
|
|
prependZero( std::to_string( values.day ), 2 ) + "T" +
|
|
prependZero( std::to_string( values.hours ), 2 ) + ":" +
|
|
prependZero( std::to_string( values.minutes ), 2 ) + ":" +
|
|
prependZero( std::to_string( int( values.seconds ) ), 2 ) +
|
|
msStr;
|
|
|
|
return strDateTime;
|
|
}
|
|
|
|
MDAL::RelativeTimestamp MDAL::DateTime::operator-( const MDAL::DateTime &other ) const
|
|
{
|
|
if ( !mValid || !other.mValid )
|
|
return RelativeTimestamp();
|
|
return RelativeTimestamp( mJulianTime - other.mJulianTime );
|
|
}
|
|
|
|
|
|
MDAL::RelativeTimestamp::RelativeTimestamp() = default;
|
|
|
|
MDAL::RelativeTimestamp::RelativeTimestamp( double duration, MDAL::RelativeTimestamp::Unit unit )
|
|
{
|
|
switch ( unit )
|
|
{
|
|
case MDAL::RelativeTimestamp::milliseconds:
|
|
mDuration = int64_t( duration );
|
|
break;
|
|
case MDAL::RelativeTimestamp::seconds:
|
|
mDuration = int64_t( duration * MILLISECONDS_IN_SECOND + 0.5 );
|
|
break;
|
|
case MDAL::RelativeTimestamp::minutes:
|
|
mDuration = int64_t( duration * MILLISECONDS_IN_MINUTE + 0.5 );
|
|
break;
|
|
case MDAL::RelativeTimestamp::hours:
|
|
mDuration = int64_t( duration * MILLISECONDS_IN_HOUR + 0.5 );
|
|
break;
|
|
case MDAL::RelativeTimestamp::days:
|
|
mDuration = int64_t( duration * MILLISECONDS_IN_DAY + 0.5 );
|
|
break;
|
|
case MDAL::RelativeTimestamp::weeks:
|
|
mDuration = int64_t( duration * MILLISECONDS_IN_WEEK + 0.5 );
|
|
break;
|
|
case MDAL::RelativeTimestamp::months_CF:
|
|
mDuration = int64_t( duration * MILLISECONDS_IN_MONTH_CF + 0.5 );
|
|
break;
|
|
case MDAL::RelativeTimestamp::exact_years:
|
|
mDuration = int64_t( duration * MILLISECONDS_IN_EXACT_YEAR + 0.5 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
double MDAL::RelativeTimestamp::value( MDAL::RelativeTimestamp::Unit unit ) const
|
|
{
|
|
switch ( unit )
|
|
{
|
|
case MDAL::RelativeTimestamp::milliseconds:
|
|
return double( mDuration );
|
|
case MDAL::RelativeTimestamp::seconds:
|
|
return mDuration / MILLISECONDS_IN_SECOND;
|
|
case MDAL::RelativeTimestamp::minutes:
|
|
return mDuration / MILLISECONDS_IN_MINUTE;
|
|
case MDAL::RelativeTimestamp::hours:
|
|
return mDuration / MILLISECONDS_IN_HOUR;
|
|
case MDAL::RelativeTimestamp::days:
|
|
return double( mDuration ) / MILLISECONDS_IN_DAY;
|
|
case MDAL::RelativeTimestamp::weeks:
|
|
return double( mDuration ) / MILLISECONDS_IN_WEEK;
|
|
case MDAL::RelativeTimestamp::months_CF:
|
|
return double( mDuration ) / MILLISECONDS_IN_MONTH_CF;
|
|
case MDAL::RelativeTimestamp::exact_years:
|
|
return double( mDuration ) / MILLISECONDS_IN_EXACT_YEAR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool MDAL::RelativeTimestamp::operator==( const MDAL::RelativeTimestamp &other ) const
|
|
{
|
|
return mDuration == other.mDuration;
|
|
}
|
|
|
|
bool MDAL::RelativeTimestamp::operator<( const MDAL::RelativeTimestamp &other ) const
|
|
{
|
|
return mDuration < other.mDuration;
|
|
}
|
|
|
|
MDAL::RelativeTimestamp::RelativeTimestamp( int64_t ms ): mDuration( ms )
|
|
{}
|