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
|
sg_time.hxx
|
||||||
timestamp.hxx
|
timestamp.hxx
|
||||||
timezone.h
|
timezone.h
|
||||||
|
zonedetect.h
|
||||||
lowleveltime.h
|
lowleveltime.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ set(SOURCES
|
|||||||
sg_time.cxx
|
sg_time.cxx
|
||||||
timestamp.cxx
|
timestamp.cxx
|
||||||
timezone.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 ( !root.isNull()) {
|
||||||
if (!static_tzContainer.get()) {
|
if (!static_tzContainer.get()) {
|
||||||
SGPath zone( root );
|
SGPath zone( root );
|
||||||
zone.append( "zone.tab" );
|
zone.append( "timezone16.bin" );
|
||||||
SG_LOG( SG_EVENT, SG_INFO, "Reading timezone info from: " << zone );
|
SG_LOG( SG_EVENT, SG_INFO, "Reading timezone info from: " << zone );
|
||||||
std::string zs = zone.utf8Str();
|
std::string zs = zone.utf8Str();
|
||||||
static_tzContainer.reset(new SGTimeZoneContainer( zs.c_str() ));
|
static_tzContainer.reset(new SGTimeZoneContainer( zs.c_str() ));
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
|
|
||||||
|
#include "zonedetect.h"
|
||||||
#include "timezone.h"
|
#include "timezone.h"
|
||||||
|
|
||||||
SGTimeZone::SGTimeZone(const SGGeod& geod, char* cc, char* desc) :
|
SGTimeZone::SGTimeZone(const SGGeod& geod, char* cc, char* desc) :
|
||||||
@ -133,14 +134,17 @@ SGTimeZone::SGTimeZone(const SGTimeZone& other)
|
|||||||
|
|
||||||
/********* Member functions for SGTimeZoneContainer class ********/
|
/********* 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];
|
char buffer[256];
|
||||||
#if defined(SG_WINDOWS)
|
#if defined(SG_WINDOWS)
|
||||||
const std::wstring wfile = simgear::strutils::convertUtf8ToWString(filename);
|
const std::wstring wfile = simgear::strutils::convertUtf8ToWString(filename);
|
||||||
FILE* infile = _wfopen(wfile.c_str(), L"rb");
|
FILE* infile = _wfopen(wfile.c_str(), L"rb");
|
||||||
#else
|
#else
|
||||||
FILE* infile = fopen(filename, "rb");
|
FILE* infile = fopen(filename, "rb");
|
||||||
#endif
|
#endif
|
||||||
if (!(infile)) {
|
if (!(infile)) {
|
||||||
std::string e = "Unable to open time zone file '";
|
std::string e = "Unable to open time zone file '";
|
||||||
@ -171,28 +175,76 @@ SGTimeZoneContainer::SGTimeZoneContainer(const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose(infile);
|
fclose(infile);
|
||||||
|
is_zone_tab = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SGTimeZoneContainer::~SGTimeZoneContainer()
|
SGTimeZoneContainer::~SGTimeZoneContainer()
|
||||||
{
|
{
|
||||||
TZVec::iterator it = zones.begin();
|
if (is_zone_tab)
|
||||||
for (; it != zones.end(); ++it) {
|
{
|
||||||
delete *it;
|
TZVec::iterator it = zones.begin();
|
||||||
|
for (; it != zones.end(); ++it) {
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SGTimeZone* SGTimeZoneContainer::getNearest(const SGGeod& ref) const
|
SGTimeZone* SGTimeZoneContainer::getNearest(const SGGeod& ref) const
|
||||||
{
|
{
|
||||||
SGVec3d refCart(SGVec3d::fromGeod(ref));
|
|
||||||
SGTimeZone* match = NULL;
|
SGTimeZone* match = NULL;
|
||||||
double minDist2 = HUGE_VAL;
|
|
||||||
|
|
||||||
TZVec::const_iterator it = zones.begin();
|
if (is_zone_tab)
|
||||||
for (; it != zones.end(); ++it) {
|
{
|
||||||
double d2 = distSqr((*it)->cartCenterpoint(), refCart);
|
SGVec3d refCart(SGVec3d::fromGeod(ref));
|
||||||
if (d2 < minDist2) {
|
double minDist2 = HUGE_VAL;
|
||||||
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;
|
SGTimeZone* getNearest(const SGGeod& ref) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string tzdb_file;
|
||||||
|
|
||||||
|
// zone.tab related
|
||||||
|
bool is_zone_tab = false;
|
||||||
typedef std::vector<SGTimeZone*> TZVec;
|
typedef std::vector<SGTimeZone*> TZVec;
|
||||||
TZVec zones;
|
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