File indexing completed on 2025-01-19 03:53:04
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2021-03-20 0007 * Description : a tool to export images to iNaturalist web service 0008 * 0009 * SPDX-FileCopyrightText: 2021 by Joerg Lohse <joergmlpts at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "inatutils.h" 0016 0017 // Qt includes 0018 0019 #include <QHttpPart> 0020 #include <QFile> 0021 #include <QFileInfo> 0022 #include <QtMath> 0023 0024 // KDE includes 0025 0026 #include <klocalizedstring.h> 0027 0028 // Local includes 0029 0030 #include "digikam_debug.h" 0031 0032 namespace DigikamGenericINatPlugin 0033 { 0034 0035 // Constants 0036 0037 const QLocale locale = QLocale(); 0038 const bool isEnglish = (locale.language() == QLocale::English) || 0039 (locale.language() == QLocale::C) || 0040 (locale.language() == QLocale::AnyLanguage); 0041 0042 const double meterInFeet = 3.28084; 0043 const double meterInMiles = 0.00062137; 0044 0045 // Functions 0046 0047 QHttpMultiPart* getMultiPart(const QList<Parameter>& parameters, 0048 const QString& imageName, 0049 const QString& imageNameArg, 0050 const QString& imagePath) 0051 { 0052 static const QString paramForm = QLatin1String("form-data; name=\"%1\""); 0053 static const QString imageForm = QLatin1String("form-data; name=\"%1\"; " 0054 "filename=\"%2\""); 0055 0056 QHttpMultiPart* const result = new QHttpMultiPart(QHttpMultiPart::FormDataType); 0057 0058 for (const auto& param : parameters) 0059 { 0060 QHttpPart part; 0061 part.setHeader(QNetworkRequest::ContentDispositionHeader, 0062 QVariant(paramForm.arg(param.first))); 0063 part.setBody(param.second.toUtf8()); 0064 result->append(part); 0065 } 0066 0067 QHttpPart imagePart; 0068 QFileInfo fileInfo(imagePath); 0069 imagePart.setHeader(QNetworkRequest::ContentTypeHeader, 0070 QVariant(QString(QLatin1String("image/%1")). 0071 arg(fileInfo.suffix().toLower()))); 0072 imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, 0073 QVariant(imageForm.arg(imageName, imageNameArg))); 0074 QFile* const file = new QFile(imagePath); 0075 0076 if (!file->open(QIODevice::ReadOnly)) 0077 { 0078 qCWarning(DIGIKAM_WEBSERVICES_LOG) << "Cannot open file to read" << imagePath; 0079 } 0080 0081 imagePart.setBodyDevice(file); 0082 file->setParent(result); 0083 result->append(imagePart); 0084 0085 return result; 0086 } 0087 0088 /** 0089 * converts degree to radian 0090 */ 0091 static inline double deg2rad(double deg) 0092 { 0093 return (deg * M_PI / 180); 0094 } 0095 0096 /** 0097 * returns distance in meters between two coordinates, Haversine formula 0098 */ 0099 double distanceBetween(double latitude1, double longitude1, 0100 double latitude2, double longitude2) 0101 { 0102 static const double earthRadiusInMeters = 6.371e6; 0103 0104 double lat1r = deg2rad(latitude1); 0105 double lon1r = deg2rad(longitude1); 0106 double lat2r = deg2rad(latitude2); 0107 double lon2r = deg2rad(longitude2); 0108 double u = sin((lat2r - lat1r) / 2); 0109 double v = sin((lon2r - lon1r) / 2); 0110 0111 return (2.0 * earthRadiusInMeters * 0112 asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v))); 0113 } 0114 0115 QString localizedTaxonomicRank(const QString& rank) 0116 { 0117 if (rank == QLatin1String("kingdom")) 0118 { 0119 return i18nc("taxonomic rank", "kingdom"); 0120 } 0121 else if (rank == QLatin1String("subkingdom")) 0122 { 0123 return i18nc("taxonomic rank", "subkingdom"); 0124 } 0125 else if (rank == QLatin1String("phylum")) 0126 { 0127 return i18nc("taxonomic rank", "phylum"); 0128 } 0129 else if (rank == QLatin1String("subphylum")) 0130 { 0131 return i18nc("taxonomic rank", "subphylum"); 0132 } 0133 else if (rank == QLatin1String("superorder")) 0134 { 0135 return i18nc("taxonomic rank", "superorder"); 0136 } 0137 else if (rank == QLatin1String("order")) 0138 { 0139 return i18nc("taxonomic rank", "order"); 0140 } 0141 else if (rank == QLatin1String("suborder")) 0142 { 0143 return i18nc("taxonomic rank", "suborder"); 0144 } 0145 else if (rank == QLatin1String("infraorder")) 0146 { 0147 return i18nc("taxonomic rank", "infraorder"); 0148 } 0149 else if (rank == QLatin1String("parvorder")) 0150 { 0151 return i18nc("taxonomic rank", "parvorder"); 0152 } 0153 else if (rank == QLatin1String("zoosection")) 0154 { 0155 return i18nc("taxonomic rank", "zoosection"); 0156 } 0157 else if (rank == QLatin1String("zoosubsection")) 0158 { 0159 return i18nc("taxonomic rank", "zoosubsection"); 0160 } 0161 else if (rank == QLatin1String("superfamily")) 0162 { 0163 return i18nc("taxonomic rank", "superfamily"); 0164 } 0165 else if (rank == QLatin1String("epifamily")) 0166 { 0167 return i18nc("taxonomic rank", "epifamily"); 0168 } 0169 else if (rank == QLatin1String("family")) 0170 { 0171 return i18nc("taxonomic rank", "family"); 0172 } 0173 else if (rank == QLatin1String("subfamily")) 0174 { 0175 return i18nc("taxonomic rank", "subfamily"); 0176 } 0177 else if (rank == QLatin1String("supertribe")) 0178 { 0179 return i18nc("taxonomic rank", "supertribe"); 0180 } 0181 else if (rank == QLatin1String("tribe")) 0182 { 0183 return i18nc("taxonomic rank", "tribe"); 0184 } 0185 else if (rank == QLatin1String("subtribe")) 0186 { 0187 return i18nc("taxonomic rank", "subtribe"); 0188 } 0189 else if (rank == QLatin1String("genus")) 0190 { 0191 return i18nc("taxonomic rank", "genus"); 0192 } 0193 else if (rank == QLatin1String("genushybrid")) 0194 { 0195 return i18nc("taxonomic rank", "genushybrid"); 0196 } 0197 else if (rank == QLatin1String("subgenus")) 0198 { 0199 return i18nc("taxonomic rank", "subgenus"); 0200 } 0201 else if (rank == QLatin1String("section")) 0202 { 0203 return i18nc("taxonomic rank", "section"); 0204 } 0205 else if (rank == QLatin1String("subsection")) 0206 { 0207 return i18nc("taxonomic rank", "subsection"); 0208 } 0209 else if (rank == QLatin1String("complex")) 0210 { 0211 return i18nc("taxonomic rank", "complex"); 0212 } 0213 else if (rank == QLatin1String("species")) 0214 { 0215 return i18nc("taxonomic rank", "species"); 0216 } 0217 else if (rank == QLatin1String("hybrid")) 0218 { 0219 return i18nc("taxonomic rank", "hybrid"); 0220 } 0221 else if (rank == QLatin1String("subspecies")) 0222 { 0223 return i18nc("taxonomic rank", "subspecies"); 0224 } 0225 else if (rank == QLatin1String("variety")) 0226 { 0227 return i18nc("taxonomic rank", "variety"); 0228 } 0229 else if (rank == QLatin1String("form")) 0230 { 0231 return i18nc("taxonomic rank", "form"); 0232 } 0233 else if (rank == QLatin1String("infrahybrid")) 0234 { 0235 return i18nc("taxonomic rank", "infrahybrid"); 0236 } 0237 else 0238 { 0239 return rank; 0240 } 0241 } 0242 0243 QString localizedLocation(double latitude, double longitude, int precision) 0244 { 0245 return (locale.toString(latitude, 'f', precision) + 0246 QLatin1String(", ") + 0247 locale.toString(longitude, 'f', precision)); 0248 } 0249 0250 QString localizedDistance(double distMeters, char format, int precision) 0251 { 0252 if (locale.measurementSystem() == QLocale::ImperialUSSystem) 0253 { 0254 if (locale.toString(distMeters * meterInMiles, format, precision) == 0255 locale.toString(0.0, format, precision)) 0256 { 0257 return locale.toString(distMeters * meterInFeet, format, precision) + 0258 QLatin1String(" ft"); 0259 } 0260 else 0261 { 0262 return locale.toString(distMeters * meterInMiles, format, 0263 precision) + QLatin1String(" mi"); 0264 } 0265 } 0266 else 0267 { 0268 if (distMeters >= 1000.0) 0269 { 0270 return locale.toString(distMeters / 1000.0, format, precision) + 0271 QLatin1String(" km"); 0272 } 0273 else 0274 { 0275 QString one = locale.toString(1.0, format, precision); 0276 QString result = locale.toString(distMeters, format, precision); 0277 0278 return (result + QLatin1Char(' ') + ((result == one) 0279 ? i18nc("distance", "meter") 0280 : i18nc("distance", "meters"))); 0281 } 0282 } 0283 } 0284 0285 QString localizedTimeDifference(quint64 diffSeconds) 0286 { 0287 QString result; 0288 0289 quint64 hours = diffSeconds / 3600; 0290 0291 if (hours) 0292 { 0293 diffSeconds %= 3600; 0294 result = QString::number(hours) + QLatin1Char(' ') + 0295 (hours == 1 ? i18nc("time", "hour") 0296 : i18nc("time", "hours")); 0297 } 0298 0299 quint64 minutes = diffSeconds / 60; 0300 0301 if (minutes) 0302 { 0303 diffSeconds %= 60; 0304 0305 if (!result.isEmpty()) 0306 { 0307 result += QLatin1String(", "); 0308 } 0309 0310 result += QString::number(minutes) + QLatin1Char(' ') + 0311 (minutes == 1 ? i18nc("time", "minute") 0312 : i18nc("time", "minutes")); 0313 } 0314 0315 if (diffSeconds || result.isEmpty()) 0316 { 0317 if (!result.isEmpty()) 0318 { 0319 result += QLatin1String(", "); 0320 } 0321 0322 result += QString::number(diffSeconds) + QLatin1Char(' ') + 0323 (diffSeconds == 1 ? i18nc("time", "second") 0324 : i18nc("time", "seconds")); 0325 } 0326 0327 return result; 0328 } 0329 0330 } // namespace DigikamGenericINatPlugin