Marble

GeoSceneTileDataset.cpp
1 /*
2  SPDX-FileCopyrightText: 2008 Torsten Rahn <[email protected]>
3  SPDX-FileCopyrightText: 2008 Jens-Michael Hoffmann <[email protected]>
4  SPDX-FileCopyrightText: 2012 Ander Pijoan <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8 
9 #include "GeoSceneTileDataset.h"
10 #include "GeoSceneTypes.h"
11 #include "GeoSceneEquirectTileProjection.h"
12 #include "GeoSceneMercatorTileProjection.h"
13 
14 #include "DownloadPolicy.h"
15 #include "MarbleDebug.h"
16 #include "MarbleDirs.h"
17 #include "ServerLayout.h"
18 #include "TileId.h"
19 
20 #include <QImage>
21 #include <QUrl>
22 
23 namespace Marble
24 {
25 
26 GeoSceneTileDataset::GeoSceneTileDataset( const QString& name )
27  : GeoSceneAbstractDataset( name ),
28  m_sourceDir(),
29  m_installMap(),
30  m_storageLayoutMode(Marble),
31  m_serverLayout( new MarbleServerLayout( this ) ),
32  m_levelZeroColumns( defaultLevelZeroColumns ),
33  m_levelZeroRows( defaultLevelZeroRows ),
34  m_minimumTileLevel(0),
35  m_maximumTileLevel( -1 ),
36  m_tileProjection(new GeoSceneEquirectTileProjection()),
37  m_blending(),
38  m_downloadUrls(),
39  m_nextUrl( m_downloadUrls.constEnd() )
40 {
41  m_tileProjection->setLevelZeroColumns(m_levelZeroColumns);
42  m_tileProjection->setLevelZeroRows(m_levelZeroRows);
43 }
44 
45 GeoSceneTileDataset::~GeoSceneTileDataset()
46 {
47  qDeleteAll( m_downloadPolicies );
48  delete m_serverLayout;
49  delete m_tileProjection;
50 }
51 
52 const char* GeoSceneTileDataset::nodeType() const
53 {
54  return GeoSceneTypes::GeoSceneTileDatasetType;
55 }
56 
57 QString GeoSceneTileDataset::sourceDir() const
58 {
59  return m_sourceDir;
60 }
61 
62 void GeoSceneTileDataset::setSourceDir( const QString& sourceDir )
63 {
64  m_sourceDir = sourceDir;
65 }
66 
67 QString GeoSceneTileDataset::installMap() const
68 {
69  return m_installMap;
70 }
71 
72 void GeoSceneTileDataset::setInstallMap( const QString& installMap )
73 {
74  m_installMap = installMap;
75 }
76 
77 GeoSceneTileDataset::StorageLayout GeoSceneTileDataset::storageLayout() const
78 {
79  return m_storageLayoutMode;
80 }
81 
82 void GeoSceneTileDataset::setStorageLayout( const StorageLayout layout )
83 {
84  m_storageLayoutMode = layout;
85 }
86 
87 void GeoSceneTileDataset::setServerLayout( const ServerLayout *layout )
88 {
89  delete m_serverLayout;
90  m_serverLayout = layout;
91 }
92 
93 const ServerLayout* GeoSceneTileDataset::serverLayout() const
94 {
95  return m_serverLayout;
96 }
97 
98 int GeoSceneTileDataset::levelZeroColumns() const
99 {
100  return m_levelZeroColumns;
101 }
102 
103 void GeoSceneTileDataset::setLevelZeroColumns( const int columns )
104 {
105  m_levelZeroColumns = columns;
106  m_tileProjection->setLevelZeroColumns(m_levelZeroColumns);
107 }
108 
109 int GeoSceneTileDataset::levelZeroRows() const
110 {
111  return m_levelZeroRows;
112 }
113 
114 void GeoSceneTileDataset::setLevelZeroRows( const int rows )
115 {
116  m_levelZeroRows = rows;
117  m_tileProjection->setLevelZeroRows(m_levelZeroRows);
118 }
119 
120 int GeoSceneTileDataset::maximumTileLevel() const
121 {
122  return m_maximumTileLevel;
123 }
124 
125 void GeoSceneTileDataset::setMaximumTileLevel( const int maximumTileLevel )
126 {
127  m_maximumTileLevel = maximumTileLevel;
128 }
129 
130 int GeoSceneTileDataset::minimumTileLevel() const
131 {
132  return m_minimumTileLevel;
133 }
134 
135 void GeoSceneTileDataset::setMinimumTileLevel(int level)
136 {
137  m_minimumTileLevel = level;
138 }
139 
140 void GeoSceneTileDataset::setTileLevels(const QString &tileLevels)
141 {
142  if (tileLevels.isEmpty()) {
143  m_tileLevels.clear();
144  return;
145  }
146 
147  const QStringList values = tileLevels.split(QLatin1Char(','));
148  for(const QString &value: values) {
149  bool canParse(false);
150  int const tileLevel = value.trimmed().toInt(&canParse);
151  if (canParse && tileLevel >= 0 && tileLevel < 100) {
152  m_tileLevels << tileLevel;
153  } else {
154  mDebug() << "Cannot parse tile level part " << value << " in " << tileLevels << ", ignoring it.";
155  }
156  }
157 
158  if (!m_tileLevels.isEmpty()) {
159  std::sort(m_tileLevels.begin(), m_tileLevels.end());
160  m_minimumTileLevel = m_tileLevels.first();
161  m_maximumTileLevel = m_tileLevels.last();
162  }
163 }
164 
165 QVector<int> GeoSceneTileDataset::tileLevels() const
166 {
167  return m_tileLevels;
168 }
169 
170 QVector<QUrl> GeoSceneTileDataset::downloadUrls() const
171 {
172  return m_downloadUrls;
173 }
174 
175 const QSize GeoSceneTileDataset::tileSize() const
176 {
177  if ( m_tileSize.isEmpty() ) {
178  const TileId id( 0, 0, 0, 0 );
179  QString const fileName = relativeTileFileName( id );
180  QFileInfo const dirInfo( fileName );
181  QString const path = dirInfo.isAbsolute() ? fileName : MarbleDirs::path( fileName );
182 
183  QImage testTile( path );
184 
185  if ( testTile.isNull() ) {
186  mDebug() << "Tile size is missing in dgml and no base tile found in " << themeStr();
187  mDebug() << "Using default tile size " << c_defaultTileSize;
188  m_tileSize = QSize( c_defaultTileSize, c_defaultTileSize );
189  } else {
190  m_tileSize = testTile.size();
191  }
192 
193  if ( m_tileSize.isEmpty() ) {
194  mDebug() << "Tile width or height cannot be 0. Falling back to default tile size.";
195  m_tileSize = QSize( c_defaultTileSize, c_defaultTileSize );
196  }
197  }
198 
199  Q_ASSERT( !m_tileSize.isEmpty() );
200  return m_tileSize;
201 }
202 
203 GeoDataLatLonBox GeoSceneTileDataset::latLonBox() const
204 {
205  return m_latLonBox;
206 }
207 
208 void GeoSceneTileDataset::setLatLonBox( const GeoDataLatLonBox &box )
209 {
210  m_latLonBox = box;
211 }
212 
213 void GeoSceneTileDataset::setTileSize( const QSize &tileSize )
214 {
215  if ( tileSize.isEmpty() ) {
216  mDebug() << "Ignoring invalid tile size " << tileSize;
217  } else {
218  m_tileSize = tileSize;
219  }
220 }
221 
222 void GeoSceneTileDataset::setTileProjection(GeoSceneAbstractTileProjection::Type projectionType)
223 {
224  if (m_tileProjection->type() == projectionType) {
225  return;
226  }
227 
228  delete m_tileProjection;
229  if (projectionType == GeoSceneAbstractTileProjection::Mercator) {
230  m_tileProjection = new GeoSceneMercatorTileProjection();
231  } else {
232  m_tileProjection = new GeoSceneEquirectTileProjection();
233  }
234 
235  m_tileProjection->setLevelZeroColumns(m_levelZeroColumns);
236  m_tileProjection->setLevelZeroRows(m_levelZeroRows);
237 }
238 
239 const GeoSceneAbstractTileProjection * GeoSceneTileDataset::tileProjection() const
240 {
241  return m_tileProjection;
242 }
243 
244 GeoSceneAbstractTileProjection::Type GeoSceneTileDataset::tileProjectionType() const
245 {
246  return m_tileProjection->type();
247 }
248 
249 // Even though this method changes the internal state, it may be const
250 // because the compiler is forced to invoke this method for different TileIds.
251 QUrl GeoSceneTileDataset::downloadUrl( const TileId &id ) const
252 {
253  // default download url
254  if ( m_downloadUrls.empty() ) {
255  QUrl const defaultUrl = QUrl(QLatin1String("https://maps.kde.org/") + m_serverLayout->sourceDir());
256  mDebug() << "No download URL specified for tiles stored in "
257  << m_sourceDir << ", falling back to " << defaultUrl.toString();
258  return m_serverLayout->downloadUrl(defaultUrl, id);
259  } else if (m_downloadUrls.size() == 1) {
260  return m_serverLayout->downloadUrl(*m_nextUrl, id);
261  } else {
262  if (m_nextUrl == m_downloadUrls.constEnd()) {
263  m_nextUrl = m_downloadUrls.constBegin();
264  }
265  const QUrl url = m_serverLayout->downloadUrl(*m_nextUrl, id);
266  ++m_nextUrl;
267  return url;
268  }
269 }
270 
271 void GeoSceneTileDataset::addDownloadUrl( const QUrl & url )
272 {
273  m_downloadUrls.append( url );
274  // FIXME: this could be done only once
275  m_nextUrl = m_downloadUrls.constBegin();
276 }
277 
278 QString GeoSceneTileDataset::relativeTileFileName( const TileId &id ) const
279 {
280  const QString suffix = fileFormat().toLower();
281 
282  QString relFileName;
283 
284  switch ( m_storageLayoutMode ) {
285  case GeoSceneTileDataset::Marble:
286  relFileName = QString( "%1/%2/%3/%3_%4.%5" )
287  .arg( themeStr() )
288  .arg( id.zoomLevel() )
289  .arg(id.y(), tileDigits, 10, QLatin1Char('0'))
290  .arg(id.x(), tileDigits, 10, QLatin1Char('0'))
291  .arg( suffix );
292  break;
293  case GeoSceneTileDataset::OpenStreetMap:
294  relFileName = QString( "%1/%2/%3/%4.%5" )
295  .arg( themeStr() )
296  .arg( id.zoomLevel() )
297  .arg( id.x() )
298  .arg( id.y() )
299  .arg( suffix );
300  break;
301  case GeoSceneTileDataset::TileMapService:
302  relFileName = QString( "%1/%2/%3/%4.%5" )
303  .arg( themeStr() )
304  .arg( id.zoomLevel() )
305  .arg( id.x() )
306  .arg( ( 1<<id.zoomLevel() ) - id.y() - 1 ) //Y coord in TMS runs from bottom to top
307  .arg( suffix );
308  break;
309  }
310 
311  return relFileName;
312 }
313 
314 QString GeoSceneTileDataset::themeStr() const
315 {
316  QFileInfo const dirInfo( sourceDir() );
317  return dirInfo.isAbsolute() ? sourceDir() : QLatin1String("maps/") + sourceDir();
318 }
319 
320 QList<const DownloadPolicy *> GeoSceneTileDataset::downloadPolicies() const
321 {
322  return m_downloadPolicies;
323 }
324 
325 void GeoSceneTileDataset::addDownloadPolicy( const DownloadUsage usage, const int maximumConnections )
326 {
327  DownloadPolicy * const policy = new DownloadPolicy( DownloadPolicyKey( hostNames(), usage ));
328  policy->setMaximumConnections( maximumConnections );
329  m_downloadPolicies.append( policy );
330  mDebug() << "added download policy" << hostNames() << usage << maximumConnections;
331 }
332 
333 QStringList GeoSceneTileDataset::hostNames() const
334 {
335  QStringList result;
336  result.reserve(m_downloadUrls.size());
337 
338  QVector<QUrl>::const_iterator pos = m_downloadUrls.constBegin();
339  QVector<QUrl>::const_iterator const end = m_downloadUrls.constEnd();
340  for (; pos != end; ++pos )
341  result.append( (*pos).host() );
342  return result;
343 }
344 
345 }
void append(const T &value)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
DownloadUsage
This enum is used to describe the type of download.
Definition: MarbleGlobal.h:153
QStringView level(QStringView ifopt)
void reserve(int alloc)
QString toString(QUrl::FormattingOptions options) const const
QString::const_iterator constBegin() const const
bool isEmpty() const const
Binds a QML item to a specific geodetic location in screen coordinates.
QString toLower() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString path(const QString &relativePath)
const char * name(StandardAction id)
QVector::const_iterator constBegin() const const
QVector< V > values(const QMultiHash< K, V > &c)
const QList< QKeySequence > & end()
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.