1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtLocation module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include <QtPositioning/private/qwebmercator_p.h> |
38 | #include "qgeocameracapabilities_p.h" |
39 | #include "qgeotiledmappingmanagerengine_nokia.h" |
40 | #include "qgeotiledmap_nokia.h" |
41 | #include "qgeotilefetcher_nokia.h" |
42 | #include "qgeotilespec_p.h" |
43 | #include "qgeofiletilecachenokia.h" |
44 | |
45 | #include <QDebug> |
46 | #include <QDir> |
47 | #include <QVariant> |
48 | #include <QtCore/QJsonArray> |
49 | #include <QtCore/QJsonObject> |
50 | #include <QtCore/QJsonDocument> |
51 | #include <QtCore/qmath.h> |
52 | #include <QtCore/qstandardpaths.h> |
53 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | QGeoTiledMappingManagerEngineNokia::QGeoTiledMappingManagerEngineNokia( |
57 | QGeoNetworkAccessManager *networkManager, |
58 | const QVariantMap ¶meters, |
59 | QGeoServiceProvider::Error *error, |
60 | QString *errorString) |
61 | : QGeoTiledMappingManagerEngine() |
62 | { |
63 | Q_UNUSED(error); |
64 | Q_UNUSED(errorString); |
65 | |
66 | int ppi = 72; |
67 | if (parameters.contains(QStringLiteral("here.mapping.highdpi_tiles" ))) { |
68 | const QString param = parameters.value(QStringLiteral("here.mapping.highdpi_tiles" )).toString().toLower(); |
69 | if (param == "true" ) |
70 | ppi = 250; |
71 | } |
72 | |
73 | QGeoCameraCapabilities capabilities; |
74 | |
75 | capabilities.setMinimumZoomLevel(0.0); |
76 | capabilities.setMaximumZoomLevel(20.0); |
77 | if (ppi > 72) { |
78 | // Zoom levels 0 and 20 are not supported for 512x512 tiles. |
79 | capabilities.setMinimumZoomLevel(1.0); |
80 | capabilities.setMaximumZoomLevel(19.0); |
81 | } |
82 | capabilities.setSupportsBearing(true); |
83 | capabilities.setSupportsTilting(true); |
84 | capabilities.setMinimumTilt(0); |
85 | capabilities.setMaximumTilt(80); |
86 | capabilities.setMinimumFieldOfView(20.0); |
87 | capabilities.setMaximumFieldOfView(120.0); |
88 | capabilities.setOverzoomEnabled(true); |
89 | setCameraCapabilities(capabilities); |
90 | |
91 | setTileSize(QSize(256, 256)); |
92 | |
93 | int mapId = 0; |
94 | const QByteArray pluginName = "here" ; |
95 | QList<QGeoMapType> types; |
96 | types << QGeoMapType(QGeoMapType::StreetMap, tr(s: "Street Map" ), tr(s: "Normal map view in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
97 | types << QGeoMapType(QGeoMapType::SatelliteMapDay, tr(s: "Satellite Map" ), tr(s: "Satellite map view in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
98 | types << QGeoMapType(QGeoMapType::TerrainMap, tr(s: "Terrain Map" ), tr(s: "Terrain map view in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
99 | types << QGeoMapType(QGeoMapType::HybridMap, tr(s: "Hybrid Map" ), tr(s: "Satellite map view with streets in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
100 | types << QGeoMapType(QGeoMapType::TransitMap, tr(s: "Transit Map" ), tr(s: "Color-reduced map view with public transport scheme in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
101 | types << QGeoMapType(QGeoMapType::GrayStreetMap, tr(s: "Gray Street Map" ), tr(s: "Color-reduced map view in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
102 | types << QGeoMapType(QGeoMapType::StreetMap, tr(s: "Mobile Street Map" ), tr(s: "Mobile normal map view in daylight mode" ), true, false, ++mapId, pluginName, capabilities); |
103 | types << QGeoMapType(QGeoMapType::TerrainMap, tr(s: "Mobile Terrain Map" ), tr(s: "Mobile terrain map view in daylight mode" ), true, false, ++mapId, pluginName, capabilities); |
104 | types << QGeoMapType(QGeoMapType::HybridMap, tr(s: "Mobile Hybrid Map" ), tr(s: "Mobile satellite map view with streets in daylight mode" ), true, false, ++mapId, pluginName, capabilities); |
105 | types << QGeoMapType(QGeoMapType::TransitMap, tr(s: "Mobile Transit Map" ), tr(s: "Mobile color-reduced map view with public transport scheme in daylight mode" ), true, false, ++mapId, pluginName, capabilities); |
106 | types << QGeoMapType(QGeoMapType::GrayStreetMap, tr(s: "Mobile Gray Street Map" ), tr(s: "Mobile color-reduced map view in daylight mode" ), true, false, ++mapId, pluginName, capabilities); |
107 | types << QGeoMapType(QGeoMapType::StreetMap, tr(s: "Custom Street Map" ), tr(s: "Normal map view in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
108 | types << QGeoMapType(QGeoMapType::StreetMap, tr(s: "Night Street Map" ), tr(s: "Normal map view in night mode" ), false, true, ++mapId, pluginName, capabilities); |
109 | types << QGeoMapType(QGeoMapType::StreetMap, tr(s: "Mobile Night Street Map" ), tr(s: "Mobile normal map view in night mode" ), true, true, ++mapId, pluginName, capabilities); |
110 | types << QGeoMapType(QGeoMapType::GrayStreetMap, tr(s: "Gray Night Street Map" ), tr(s: "Color-reduced map view in night mode (especially used for background maps)" ), false, true, ++mapId, pluginName, capabilities); |
111 | types << QGeoMapType(QGeoMapType::GrayStreetMap, tr(s: "Mobile Gray Night Street Map" ), tr(s: "Mobile color-reduced map view in night mode (especially used for background maps)" ), true, true, ++mapId, pluginName, capabilities); |
112 | types << QGeoMapType(QGeoMapType::PedestrianMap, tr(s: "Pedestrian Street Map" ), tr(s: "Pedestrian map view in daylight mode" ), false, false, ++mapId, pluginName, capabilities); |
113 | types << QGeoMapType(QGeoMapType::PedestrianMap, tr(s: "Mobile Pedestrian Street Map" ), tr(s: "Mobile pedestrian map view in daylight mode for mobile usage" ), true, false, ++mapId, pluginName, capabilities); |
114 | types << QGeoMapType(QGeoMapType::PedestrianMap, tr(s: "Pedestrian Night Street Map" ), tr(s: "Pedestrian map view in night mode" ), false, true, ++mapId, pluginName, capabilities); |
115 | types << QGeoMapType(QGeoMapType::PedestrianMap, tr(s: "Mobile Pedestrian Night Street Map" ), tr(s: "Mobile pedestrian map view in night mode for mobile usage" ), true, true, ++mapId, pluginName, capabilities); |
116 | types << QGeoMapType(QGeoMapType::CarNavigationMap, tr(s: "Car Navigation Map" ), tr(s: "Normal map view in daylight mode for car navigation" ), false, false, ++mapId, pluginName, capabilities); |
117 | setSupportedMapTypes(types); |
118 | |
119 | QGeoTileFetcherNokia *fetcher = new QGeoTileFetcherNokia(parameters, networkManager, this, tileSize(), ppi); |
120 | setTileFetcher(fetcher); |
121 | |
122 | /* TILE CACHE */ |
123 | // TODO: do this in a plugin-neutral way so that other tiled map plugins |
124 | // don't need this boilerplate or hardcode plugin name |
125 | if (parameters.contains(QStringLiteral("here.mapping.cache.directory" ))) { |
126 | m_cacheDirectory = parameters.value(QStringLiteral("here.mapping.cache.directory" )).toString(); |
127 | } else { |
128 | // managerName() is not yet set, we have to hardcode the plugin name below |
129 | m_cacheDirectory = QAbstractGeoTileCache::baseLocationCacheDirectory() + QLatin1String(pluginName); |
130 | } |
131 | |
132 | QGeoFileTileCache *tileCache = new QGeoFileTileCacheNokia(ppi, m_cacheDirectory); |
133 | |
134 | /* |
135 | * Disk cache setup -- defaults to ByteSize (old behavior) |
136 | */ |
137 | if (parameters.contains(QStringLiteral("here.mapping.cache.disk.cost_strategy" ))) { |
138 | QString cacheStrategy = parameters.value(QStringLiteral("here.mapping.cache.disk.cost_strategy" )).toString().toLower(); |
139 | if (cacheStrategy == QLatin1String("bytesize" )) |
140 | tileCache->setCostStrategyDisk(QGeoFileTileCache::ByteSize); |
141 | else |
142 | tileCache->setCostStrategyDisk(QGeoFileTileCache::Unitary); |
143 | } else { |
144 | tileCache->setCostStrategyDisk(QGeoFileTileCache::ByteSize); |
145 | } |
146 | if (parameters.contains(QStringLiteral("here.mapping.cache.disk.size" ))) { |
147 | bool ok = false; |
148 | int cacheSize = parameters.value(QStringLiteral("here.mapping.cache.disk.size" )).toString().toInt(ok: &ok); |
149 | if (ok) |
150 | tileCache->setMaxDiskUsage(cacheSize); |
151 | } |
152 | |
153 | /* |
154 | * Memory cache setup -- defaults to ByteSize (old behavior) |
155 | */ |
156 | if (parameters.contains(QStringLiteral("here.mapping.cache.memory.cost_strategy" ))) { |
157 | QString cacheStrategy = parameters.value(QStringLiteral("here.mapping.cache.memory.cost_strategy" )).toString().toLower(); |
158 | if (cacheStrategy == QLatin1String("bytesize" )) |
159 | tileCache->setCostStrategyMemory(QGeoFileTileCache::ByteSize); |
160 | else |
161 | tileCache->setCostStrategyMemory(QGeoFileTileCache::Unitary); |
162 | } else { |
163 | tileCache->setCostStrategyMemory(QGeoFileTileCache::ByteSize); |
164 | } |
165 | if (parameters.contains(QStringLiteral("here.mapping.cache.memory.size" ))) { |
166 | bool ok = false; |
167 | int cacheSize = parameters.value(QStringLiteral("here.mapping.cache.memory.size" )).toString().toInt(ok: &ok); |
168 | if (ok) |
169 | tileCache->setMaxMemoryUsage(cacheSize); |
170 | } |
171 | |
172 | /* |
173 | * Texture cache setup -- defaults to ByteSize (old behavior) |
174 | */ |
175 | if (parameters.contains(QStringLiteral("here.mapping.cache.texture.cost_strategy" ))) { |
176 | QString cacheStrategy = parameters.value(QStringLiteral("here.mapping.cache.texture.cost_strategy" )).toString().toLower(); |
177 | if (cacheStrategy == QLatin1String("bytesize" )) |
178 | tileCache->setCostStrategyTexture(QGeoFileTileCache::ByteSize); |
179 | else |
180 | tileCache->setCostStrategyTexture(QGeoFileTileCache::Unitary); |
181 | } else { |
182 | tileCache->setCostStrategyTexture(QGeoFileTileCache::ByteSize); |
183 | } |
184 | if (parameters.contains(QStringLiteral("here.mapping.cache.texture.size" ))) { |
185 | bool ok = false; |
186 | int cacheSize = parameters.value(QStringLiteral("here.mapping.cache.texture.size" )).toString().toInt(ok: &ok); |
187 | if (ok) |
188 | tileCache->setExtraTextureUsage(cacheSize); |
189 | } |
190 | |
191 | /* PREFETCHING */ |
192 | if (parameters.contains(QStringLiteral("here.mapping.prefetching_style" ))) { |
193 | const QString prefetchingMode = parameters.value(QStringLiteral("here.mapping.prefetching_style" )).toString(); |
194 | if (prefetchingMode == QStringLiteral("TwoNeighbourLayers" )) |
195 | m_prefetchStyle = QGeoTiledMap::PrefetchTwoNeighbourLayers; |
196 | else if (prefetchingMode == QStringLiteral("OneNeighbourLayer" )) |
197 | m_prefetchStyle = QGeoTiledMap::PrefetchNeighbourLayer; |
198 | else if (prefetchingMode == QStringLiteral("NoPrefetching" )) |
199 | m_prefetchStyle = QGeoTiledMap::NoPrefetching; |
200 | } |
201 | |
202 | setTileCache(tileCache); |
203 | populateMapSchemes(); |
204 | loadMapVersion(); |
205 | QMetaObject::invokeMethod(obj: fetcher, member: "fetchCopyrightsData" , type: Qt::QueuedConnection); |
206 | QMetaObject::invokeMethod(obj: fetcher, member: "fetchVersionData" , type: Qt::QueuedConnection); |
207 | } |
208 | |
209 | QGeoTiledMappingManagerEngineNokia::~QGeoTiledMappingManagerEngineNokia() |
210 | { |
211 | } |
212 | |
213 | void QGeoTiledMappingManagerEngineNokia::populateMapSchemes() |
214 | { |
215 | m_mapSchemes[0] = QStringLiteral("normal.day" ); |
216 | m_mapSchemes[1] = QStringLiteral("normal.day" ); |
217 | m_mapSchemes[2] = QStringLiteral("satellite.day" ); |
218 | m_mapSchemes[3] = QStringLiteral("terrain.day" ); |
219 | m_mapSchemes[4] = QStringLiteral("hybrid.day" ); |
220 | m_mapSchemes[5] = QStringLiteral("normal.day.transit" ); |
221 | m_mapSchemes[6] = QStringLiteral("normal.day.grey" ); |
222 | m_mapSchemes[7] = QStringLiteral("normal.day.mobile" ); |
223 | m_mapSchemes[8] = QStringLiteral("terrain.day.mobile" ); |
224 | m_mapSchemes[9] = QStringLiteral("hybrid.day.mobile" ); |
225 | m_mapSchemes[10] = QStringLiteral("normal.day.transit.mobile" ); |
226 | m_mapSchemes[11] = QStringLiteral("normal.day.grey.mobile" ); |
227 | m_mapSchemes[12] = QStringLiteral("normal.day.custom" ); |
228 | m_mapSchemes[13] = QStringLiteral("normal.night" ); |
229 | m_mapSchemes[14] = QStringLiteral("normal.night.mobile" ); |
230 | m_mapSchemes[15] = QStringLiteral("normal.night.grey" ); |
231 | m_mapSchemes[16] = QStringLiteral("normal.night.grey.mobile" ); |
232 | m_mapSchemes[17] = QStringLiteral("pedestrian.day" ); |
233 | m_mapSchemes[18] = QStringLiteral("pedestrian.day.mobile" ); |
234 | m_mapSchemes[19] = QStringLiteral("pedestrian.night" ); |
235 | m_mapSchemes[20] = QStringLiteral("pedestrian.night.mobile" ); |
236 | m_mapSchemes[21] = QStringLiteral("carnav.day.grey" ); |
237 | } |
238 | |
239 | QString QGeoTiledMappingManagerEngineNokia::getScheme(int mapId) |
240 | { |
241 | return m_mapSchemes[mapId]; |
242 | } |
243 | |
244 | QString QGeoTiledMappingManagerEngineNokia::getBaseScheme(int mapId) |
245 | { |
246 | QString fullScheme(m_mapSchemes[mapId]); |
247 | |
248 | return fullScheme.section(asep: QLatin1Char('.'), astart: 0, aend: 0); |
249 | } |
250 | |
251 | int QGeoTiledMappingManagerEngineNokia::mapVersion() |
252 | { |
253 | return m_mapVersion.version(); |
254 | } |
255 | |
256 | void QGeoTiledMappingManagerEngineNokia::loadCopyrightsDescriptorsFromJson(const QByteArray &jsonData) |
257 | { |
258 | QJsonDocument doc = QJsonDocument::fromJson(json: QByteArray(jsonData)); |
259 | if (doc.isNull()) { |
260 | qDebug() << "QGeoTiledMappingManagerEngineNokia::loadCopyrightsDescriptorsFromJson() Invalid JSon document" ; |
261 | return; |
262 | } |
263 | |
264 | QJsonObject jsonObj = doc.object(); |
265 | |
266 | m_copyrights.clear(); |
267 | for (auto it = jsonObj.constBegin(), end = jsonObj.constEnd(); it != end; ++it) { |
268 | QList<CopyrightDesc> copyrightDescList; |
269 | |
270 | QJsonArray descs = it.value().toArray(); |
271 | for (int descIndex = 0; descIndex < descs.count(); descIndex++) { |
272 | CopyrightDesc copyrightDesc; |
273 | QJsonObject desc = descs.at(i: descIndex).toObject(); |
274 | |
275 | copyrightDesc.minLevel = desc["minLevel" ].toDouble(); |
276 | copyrightDesc.maxLevel = desc["maxLevel" ].toDouble(); |
277 | copyrightDesc.label = desc["label" ].toString(); |
278 | copyrightDesc.alt = desc["alt" ].toString(); |
279 | |
280 | QJsonArray coordBoxes = desc["boxes" ].toArray(); |
281 | for (int boxIndex = 0; boxIndex < coordBoxes.count(); boxIndex++) { |
282 | QJsonArray box = coordBoxes[boxIndex].toArray(); |
283 | qreal top = box[0].toDouble(); |
284 | qreal left = box[1].toDouble(); |
285 | qreal bottom = box[2].toDouble(); |
286 | qreal right = box[3].toDouble(); |
287 | QGeoRectangle boundingBox(QGeoCoordinate(top > bottom? top : bottom, |
288 | left), |
289 | QGeoCoordinate(top > bottom? bottom : top, |
290 | right)); |
291 | copyrightDesc.boxes << boundingBox; |
292 | } |
293 | copyrightDescList << copyrightDesc; |
294 | } |
295 | m_copyrights[it.key()] = copyrightDescList; |
296 | } |
297 | } |
298 | |
299 | void QGeoTiledMappingManagerEngineNokia::parseNewVersionInfo(const QByteArray &versionData) |
300 | { |
301 | const QString versionString = QString::fromUtf8(str: versionData); |
302 | |
303 | const QStringList versionLines = versionString.split(sep: QLatin1Char('\n')); |
304 | QJsonObject newVersionData; |
305 | foreach (const QString &line, versionLines) { |
306 | const QStringList versionInfo = line.split(sep: ':'); |
307 | if (versionInfo.size() > 1) { |
308 | const QString versionKey = versionInfo[0].trimmed(); |
309 | const QString versionValue = versionInfo[1].trimmed(); |
310 | if (!versionKey.isEmpty() && !versionValue.isEmpty()) { |
311 | newVersionData[versionKey] = versionValue; |
312 | } |
313 | } |
314 | } |
315 | |
316 | updateVersion(newVersionData); |
317 | } |
318 | |
319 | void QGeoTiledMappingManagerEngineNokia::updateVersion(const QJsonObject &newVersionData) { |
320 | |
321 | if (m_mapVersion.isNewVersion(newVersionData)) { |
322 | |
323 | m_mapVersion.setVersionData(newVersionData); |
324 | m_mapVersion.setVersion(m_mapVersion.version() + 1); |
325 | |
326 | saveMapVersion(); |
327 | setTileVersion(m_mapVersion.version()); |
328 | } |
329 | } |
330 | |
331 | void QGeoTiledMappingManagerEngineNokia::saveMapVersion() |
332 | { |
333 | QDir saveDir(m_cacheDirectory); |
334 | QFile saveFile(saveDir.filePath(QStringLiteral("here_version" ))); |
335 | |
336 | if (!saveFile.open(flags: QIODevice::WriteOnly)) { |
337 | qWarning(msg: "Failed to write here/nokia map version." ); |
338 | return; |
339 | } |
340 | |
341 | saveFile.write(data: m_mapVersion.toJson()); |
342 | saveFile.close(); |
343 | } |
344 | |
345 | void QGeoTiledMappingManagerEngineNokia::loadMapVersion() |
346 | { |
347 | QDir saveDir(m_cacheDirectory); |
348 | QFile loadFile(saveDir.filePath(QStringLiteral("here_version" ))); |
349 | |
350 | if (!loadFile.open(flags: QIODevice::ReadOnly)) { |
351 | qWarning(msg: "Failed to read here/nokia map version." ); |
352 | return; |
353 | } |
354 | |
355 | QByteArray saveData = loadFile.readAll(); |
356 | loadFile.close(); |
357 | |
358 | QJsonDocument doc(QJsonDocument::fromJson(json: saveData)); |
359 | |
360 | QJsonObject object = doc.object(); |
361 | |
362 | m_mapVersion.setVersion(object[QStringLiteral("version" )].toInt()); |
363 | m_mapVersion.setVersionData(object[QStringLiteral("data" )].toObject()); |
364 | setTileVersion(m_mapVersion.version()); |
365 | } |
366 | |
367 | QString QGeoTiledMappingManagerEngineNokia::evaluateCopyrightsText(const QGeoMapType mapType, |
368 | const qreal zoomLevel, |
369 | const QSet<QGeoTileSpec> &tiles) |
370 | { |
371 | static const QChar copyrightSymbol(0x00a9); |
372 | typedef QSet<QGeoTileSpec>::const_iterator tile_iter; |
373 | QGeoRectangle viewport; |
374 | double viewX0, viewY0, viewX1, viewY1; |
375 | |
376 | tile_iter tile = tiles.constBegin(); |
377 | tile_iter lastTile = tiles.constEnd(); |
378 | |
379 | if (tiles.count()) { |
380 | double divFactor = qPow(x: 2.0, y: tile->zoom()); |
381 | viewX0 = viewX1 = tile->x(); |
382 | viewY0 = viewY1 = tile->y(); |
383 | |
384 | // this approach establishes a geo-bounding box from passed tiles to test for intersecition |
385 | // with copyrights boxes. |
386 | int numTiles = 0; |
387 | for (; tile != lastTile; ++tile) { |
388 | if (tile->x() < viewX0) |
389 | viewX0 = tile->x(); |
390 | if (tile->x() > viewX1) |
391 | viewX1 = tile->x(); |
392 | if (tile->y() < viewY0) |
393 | viewY0 = tile->y(); |
394 | if (tile->y() > viewY1) |
395 | viewY1 = tile->y(); |
396 | numTiles++; |
397 | } |
398 | |
399 | viewX1++; |
400 | viewY1++; |
401 | |
402 | QDoubleVector2D pt; |
403 | |
404 | pt.setX(viewX0 / divFactor); |
405 | pt.setY(viewY0 / divFactor); |
406 | viewport.setTopLeft(QWebMercator::mercatorToCoord(mercator: pt)); |
407 | pt.setX(viewX1 / divFactor); |
408 | pt.setY(viewY1 / divFactor); |
409 | viewport.setBottomRight(QWebMercator::mercatorToCoord(mercator: pt)); |
410 | } |
411 | |
412 | // TODO: the following invalidation detection algorithm may be improved later. |
413 | QList<CopyrightDesc> descriptorList = m_copyrights[ getBaseScheme(mapId: mapType.mapId()) ]; |
414 | CopyrightDesc *descriptor; |
415 | int descIndex, boxIndex; |
416 | QString copyrightsText; |
417 | QSet<QString> copyrightStrings; |
418 | |
419 | for (descIndex = 0; descIndex < descriptorList.count(); descIndex++) { |
420 | if (descriptorList[descIndex].minLevel <= zoomLevel && zoomLevel <= descriptorList[descIndex].maxLevel) { |
421 | descriptor = &descriptorList[descIndex]; |
422 | |
423 | for (boxIndex = 0; boxIndex < descriptor->boxes.count(); boxIndex++) { |
424 | QGeoRectangle box = descriptor->boxes[boxIndex]; |
425 | |
426 | if (box.intersects(rectangle: viewport)) { |
427 | copyrightStrings.insert(value: descriptor->label); |
428 | break; |
429 | } |
430 | } |
431 | if (!descriptor->boxes.count()) |
432 | copyrightStrings.insert(value: descriptor->label); |
433 | } |
434 | } |
435 | |
436 | foreach (const QString ©rightString, copyrightStrings) { |
437 | if (copyrightsText.length()) |
438 | copyrightsText += QLatin1Char('\n'); |
439 | copyrightsText += copyrightSymbol; |
440 | copyrightsText += copyrightString; |
441 | } |
442 | |
443 | return copyrightsText; |
444 | } |
445 | |
446 | QGeoMap *QGeoTiledMappingManagerEngineNokia::createMap() |
447 | { |
448 | QGeoTiledMap *map = new QGeoTiledMapNokia(this); |
449 | map->setPrefetchStyle(m_prefetchStyle); |
450 | return map; |
451 | } |
452 | |
453 | QT_END_NAMESPACE |
454 | |
455 | |