File indexing completed on 2024-05-12 15:54:51

0001 /*
0002  * SPDX-FileCopyrightText: (C) 2015 Vishesh Handa <me@vhanda.in>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  */
0006 
0007 #include "reversegeocoder.h"
0008 
0009 #include <QFile>
0010 #include <QStandardPaths>
0011 #include <QTextStream>
0012 
0013 #include <QDebug>
0014 #include <QMutexLocker>
0015 
0016 using namespace Koko;
0017 
0018 ReverseGeoCoder::~ReverseGeoCoder()
0019 {
0020     deinit();
0021 }
0022 
0023 void ReverseGeoCoder::init()
0024 {
0025     QString citiesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, "cities1000.txt");
0026     Q_ASSERT(!citiesPath.isEmpty());
0027 
0028     QFile file(citiesPath);
0029     if (!file.open(QIODevice::ReadOnly)) {
0030         Q_ASSERT_X(0, "", "Failed to open cities1000.txt file");
0031     }
0032     QTextStream fstream(&file);
0033 
0034     while (!fstream.atEnd()) {
0035         QString str = fstream.readLine();
0036         str.remove('\r');
0037 
0038         QStringList list = str.split('\t');
0039 
0040         // int geoId = list[0].toInt();
0041         // QString name = list[1];
0042         double lat = list[4].toDouble();
0043         double lon = list[5].toDouble();
0044 
0045         QString countryCode = list[8];
0046         QString admin1Code = list[10];
0047         QString admin2Code = list[11];
0048 
0049         QVariantMap map = QVariantMap();
0050         // map.insert("geoId", geoId);
0051         // map.insert("name", name);
0052         map.insert("countryCode", countryCode);
0053         map.insert("admin1Code", admin1Code);
0054         map.insert("admin2Code", admin2Code);
0055 
0056         m_tree.insert(lat, lon, map);
0057     }
0058 
0059     // Country
0060     QString countryPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, "countries.csv");
0061     Q_ASSERT(!countryPath.isEmpty());
0062 
0063     QFile cFile(countryPath);
0064     if (!cFile.open(QIODevice::ReadOnly)) {
0065         Q_ASSERT_X(0, "", "Failed to open countries.csv file");
0066     }
0067     QTextStream cstream(&cFile);
0068 
0069     while (!cstream.atEnd()) {
0070         QString str = cstream.readLine();
0071 
0072         QStringList list = str.split(',');
0073 
0074         QString code = list[0];
0075         QString name = list[1];
0076         m_countryMap.insert(code, name);
0077     }
0078     Q_ASSERT_X(!m_countryMap.isEmpty(), "", "countries.csv file is empty. Packaging issue");
0079 
0080     // Admin1
0081     QString admin1Path = QStandardPaths::locate(QStandardPaths::AppDataLocation, "admin1Codes.txt");
0082     Q_ASSERT(!admin1Path.isEmpty());
0083 
0084     QFile admin1File(admin1Path);
0085     if (!admin1File.open(QIODevice::ReadOnly)) {
0086         Q_ASSERT_X(0, "", "Failed to open admin1Codes.txt file");
0087     }
0088     QTextStream a1fstream(&admin1File);
0089 
0090     while (!a1fstream.atEnd()) {
0091         QString str = a1fstream.readLine();
0092         str.remove('\r');
0093 
0094         QStringList list = str.split('\t');
0095 
0096         QString code = list[0];
0097         QString name = list[1];
0098         m_admin1Map.insert(code, name);
0099     }
0100     Q_ASSERT_X(!m_admin1Map.isEmpty(), "", "admin1Codes.txt file is empty. Packaging issue");
0101 
0102     // Admin2
0103     QString admin2Path = QStandardPaths::locate(QStandardPaths::AppDataLocation, "admin2Codes.txt");
0104     Q_ASSERT(!admin2Path.isEmpty());
0105 
0106     QFile admin2File(admin2Path);
0107     if (!admin2File.open(QIODevice::ReadOnly)) {
0108         Q_ASSERT_X(0, "", "Failed to open admin2Codes.txt file");
0109     }
0110     QTextStream a2fstream(&admin2File);
0111 
0112     while (!a2fstream.atEnd()) {
0113         QString str = a2fstream.readLine();
0114         str.remove('\r');
0115 
0116         QStringList list = str.split('\t');
0117 
0118         QString code = list[0];
0119         QString name = list[1];
0120         m_admin2Map.insert(code, name);
0121     }
0122     Q_ASSERT_X(!m_admin2Map.isEmpty(), "", "admin2Codes.txt file is empty. Packaging issue");
0123 }
0124 
0125 void ReverseGeoCoder::deinit()
0126 {
0127     QMutexLocker locker(&m_mutex);
0128 
0129     m_tree.clear();
0130     m_countryMap.clear();
0131     m_admin1Map.clear();
0132     m_admin2Map.clear();
0133 }
0134 
0135 bool ReverseGeoCoder::initialized()
0136 {
0137     return !m_tree.isEmpty();
0138 }
0139 
0140 QVariantMap ReverseGeoCoder::lookup(double lat, double lon)
0141 {
0142     QMutexLocker locker(&m_mutex);
0143     if (!initialized()) {
0144         init();
0145     }
0146     Q_ASSERT(!m_tree.isEmpty());
0147 
0148     KdNode *res = m_tree.findNearest(lat, lon);
0149     if (res == nullptr) {
0150         return QVariantMap();
0151     }
0152 
0153     QVariantMap map = res->data;
0154 
0155     QString country = map.value("countryCode").toString();
0156     QString admin1 = country + '.' + map.value("admin1Code").toString();
0157     QString admin2 = admin1 + '.' + map.value("admin2Code").toString();
0158 
0159     QVariantMap vMap;
0160     vMap.insert("country", m_countryMap.value(country));
0161     vMap.insert("admin1", m_admin1Map.value(admin1));
0162     vMap.insert("admin2", m_admin2Map.value(admin2));
0163 
0164     return vMap;
0165 }