Use a vector database to get the timezone based on territorial boundaries
This commit is contained in:
parent
bbd84a944a
commit
c9e24dcb0b
@ -6,6 +6,7 @@ set(HEADERS
|
||||
sg_time.hxx
|
||||
timestamp.hxx
|
||||
timezone.h
|
||||
zonedetect.h
|
||||
lowleveltime.h
|
||||
)
|
||||
|
||||
@ -14,6 +15,7 @@ set(SOURCES
|
||||
sg_time.cxx
|
||||
timestamp.cxx
|
||||
timezone.cxx
|
||||
zonedetect.c
|
||||
)
|
||||
|
||||
simgear_component(timing timing "${SOURCES}" "${HEADERS}")
|
||||
simgear_component(timing timing "${SOURCES}" "${HEADERS}")
|
||||
|
9
simgear/timing/README
Normal file
9
simgear/timing/README
Normal file
@ -0,0 +1,9 @@
|
||||
ZoneDetect: BSD-3-Clause License
|
||||
https://github.com/BertoldVdb/ZoneDetect
|
||||
|
||||
This is a C library that allows you to find an area a point belongs to using a
|
||||
database file. A typical example would be looking up the country or timezone
|
||||
given a latitude and longitude. The timezone database also contains the country information.
|
||||
|
||||
download the database files:
|
||||
https://cdn.bertold.org/zonedetect/db/db.zip
|
@ -84,7 +84,7 @@ void SGTime::init( const SGGeod& location, const SGPath& root, time_t init_time
|
||||
if ( !root.isNull()) {
|
||||
if (!static_tzContainer.get()) {
|
||||
SGPath zone( root );
|
||||
zone.append( "zone.tab" );
|
||||
zone.append( "timezone16.bin" );
|
||||
SG_LOG( SG_EVENT, SG_INFO, "Reading timezone info from: " << zone );
|
||||
std::string zs = zone.utf8Str();
|
||||
static_tzContainer.reset(new SGTimeZoneContainer( zs.c_str() ));
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
|
||||
#include "zonedetect.h"
|
||||
#include "timezone.h"
|
||||
|
||||
SGTimeZone::SGTimeZone(const SGGeod& geod, char* cc, char* desc) :
|
||||
@ -133,14 +134,17 @@ SGTimeZone::SGTimeZone(const SGTimeZone& other)
|
||||
|
||||
/********* Member functions for SGTimeZoneContainer class ********/
|
||||
|
||||
SGTimeZoneContainer::SGTimeZoneContainer(const char *filename)
|
||||
SGTimeZoneContainer::SGTimeZoneContainer(const char *filename) :
|
||||
tzdb_file(filename)
|
||||
{
|
||||
if (tzdb_file.find("zone.tab") != std::string::npos)
|
||||
{
|
||||
char buffer[256];
|
||||
#if defined(SG_WINDOWS)
|
||||
const std::wstring wfile = simgear::strutils::convertUtf8ToWString(filename);
|
||||
FILE* infile = _wfopen(wfile.c_str(), L"rb");
|
||||
const std::wstring wfile = simgear::strutils::convertUtf8ToWString(filename);
|
||||
FILE* infile = _wfopen(wfile.c_str(), L"rb");
|
||||
#else
|
||||
FILE* infile = fopen(filename, "rb");
|
||||
FILE* infile = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!(infile)) {
|
||||
std::string e = "Unable to open time zone file '";
|
||||
@ -171,28 +175,76 @@ SGTimeZoneContainer::SGTimeZoneContainer(const char *filename)
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
is_zone_tab = true;
|
||||
}
|
||||
}
|
||||
|
||||
SGTimeZoneContainer::~SGTimeZoneContainer()
|
||||
{
|
||||
TZVec::iterator it = zones.begin();
|
||||
for (; it != zones.end(); ++it) {
|
||||
delete *it;
|
||||
if (is_zone_tab)
|
||||
{
|
||||
TZVec::iterator it = zones.begin();
|
||||
for (; it != zones.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SGTimeZone* SGTimeZoneContainer::getNearest(const SGGeod& ref) const
|
||||
{
|
||||
SGVec3d refCart(SGVec3d::fromGeod(ref));
|
||||
SGTimeZone* match = NULL;
|
||||
double minDist2 = HUGE_VAL;
|
||||
|
||||
if (is_zone_tab)
|
||||
{
|
||||
SGVec3d refCart(SGVec3d::fromGeod(ref));
|
||||
double minDist2 = HUGE_VAL;
|
||||
|
||||
TZVec::const_iterator it = zones.begin();
|
||||
for (; it != zones.end(); ++it) {
|
||||
double d2 = distSqr((*it)->cartCenterpoint(), refCart);
|
||||
if (d2 < minDist2) {
|
||||
match = *it;
|
||||
minDist2 = d2;
|
||||
TZVec::const_iterator it = zones.begin();
|
||||
for (; it != zones.end(); ++it) {
|
||||
double d2 = distSqr((*it)->cartCenterpoint(), refCart);
|
||||
if (d2 < minDist2) {
|
||||
match = *it;
|
||||
minDist2 = d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!tzdb_file.empty())
|
||||
{
|
||||
ZoneDetect *const cd = ZDOpenDatabase(tzdb_file.c_str());
|
||||
if (cd)
|
||||
{
|
||||
char *CountryAlpha2 = nullptr;
|
||||
char *TimezoneIdPrefix = nullptr;
|
||||
char *TimezoneId = nullptr;
|
||||
|
||||
float safezone = 0;
|
||||
float lat = ref.getLatitudeDeg();
|
||||
float lon = ref.getLongitudeDeg();
|
||||
ZoneDetectResult *results = ZDLookup(cd, lat, lon, &safezone);
|
||||
if (results && results[0].data)
|
||||
{
|
||||
for(unsigned i=0; i<results[0].numFields; ++i)
|
||||
{
|
||||
if(results[0].fieldNames[i] && results[0].data[i])
|
||||
{
|
||||
std::string fieldName = results[0].fieldNames[i];
|
||||
if (fieldName == "CountryAlpha2") {
|
||||
CountryAlpha2 = results[0].data[i];
|
||||
} else if (fieldName == "TimezoneIdPrefix") {
|
||||
TimezoneIdPrefix = results[0].data[i];
|
||||
} else if (fieldName == "TimezoneId") {
|
||||
TimezoneId = results[0].data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string desc;
|
||||
desc = TimezoneIdPrefix;
|
||||
desc += TimezoneId;
|
||||
|
||||
match = new SGTimeZone(ref, CountryAlpha2, (char*)desc.c_str());
|
||||
}
|
||||
ZDCloseDatabase(cd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,10 @@ public:
|
||||
SGTimeZone* getNearest(const SGGeod& ref) const;
|
||||
|
||||
private:
|
||||
std::string tzdb_file;
|
||||
|
||||
// zone.tab related
|
||||
bool is_zone_tab = false;
|
||||
typedef std::vector<SGTimeZone*> TZVec;
|
||||
TZVec zones;
|
||||
};
|
||||
|
1251
simgear/timing/zonedetect.c
Normal file
1251
simgear/timing/zonedetect.c
Normal file
File diff suppressed because it is too large
Load Diff
91
simgear/timing/zonedetect.h
Normal file
91
simgear/timing/zonedetect.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Bertold Van den Bergh (vandenbergh@bertold.org)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef INCL_ZONEDETECT_H_
|
||||
#define INCL_ZONEDETECT_H_
|
||||
|
||||
#if !defined(ZD_EXPORT)
|
||||
#if defined(_MSC_VER)
|
||||
#define ZD_EXPORT __declspec(dllimport)
|
||||
#else
|
||||
#define ZD_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ZD_LOOKUP_IGNORE = -3,
|
||||
ZD_LOOKUP_END = -2,
|
||||
ZD_LOOKUP_PARSE_ERROR = -1,
|
||||
ZD_LOOKUP_NOT_IN_ZONE = 0,
|
||||
ZD_LOOKUP_IN_ZONE = 1,
|
||||
ZD_LOOKUP_IN_EXCLUDED_ZONE = 2,
|
||||
ZD_LOOKUP_ON_BORDER_VERTEX = 3,
|
||||
ZD_LOOKUP_ON_BORDER_SEGMENT = 4
|
||||
} ZDLookupResult;
|
||||
|
||||
typedef struct {
|
||||
ZDLookupResult lookupResult;
|
||||
|
||||
uint32_t polygonId;
|
||||
uint32_t metaId;
|
||||
uint8_t numFields;
|
||||
char **fieldNames;
|
||||
char **data;
|
||||
} ZoneDetectResult;
|
||||
|
||||
struct ZoneDetectOpaque;
|
||||
typedef struct ZoneDetectOpaque ZoneDetect;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
ZD_EXPORT ZoneDetect *ZDOpenDatabase(const char *path);
|
||||
ZD_EXPORT ZoneDetect *ZDOpenDatabaseFromMemory(void* buffer, size_t length);
|
||||
ZD_EXPORT void ZDCloseDatabase(ZoneDetect *library);
|
||||
|
||||
ZD_EXPORT ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, float *safezone);
|
||||
ZD_EXPORT void ZDFreeResults(ZoneDetectResult *results);
|
||||
|
||||
ZD_EXPORT const char *ZDGetNotice(const ZoneDetect *library);
|
||||
ZD_EXPORT uint8_t ZDGetTableType(const ZoneDetect *library);
|
||||
ZD_EXPORT const char *ZDLookupResultToString(ZDLookupResult result);
|
||||
|
||||
ZD_EXPORT int ZDSetErrorHandler(void (*handler)(int, int));
|
||||
ZD_EXPORT const char *ZDGetErrorString(int errZD);
|
||||
|
||||
ZD_EXPORT float* ZDPolygonToList(const ZoneDetect *library, uint32_t polygonId, size_t* length);
|
||||
|
||||
ZD_EXPORT char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // INCL_ZONEDETECT_H_
|
Loading…
Reference in New Issue
Block a user