QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsvectortileutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectortileutils.cpp
3  --------------------------------------
4  Date : March 2020
5  Copyright : (C) 2020 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsvectortileutils.h"
17 
18 #include <math.h>
19 
20 #include <QPolygon>
21 
22 #include "qgscoordinatetransform.h"
23 #include "qgsgeometrycollection.h"
24 #include "qgsfields.h"
25 #include "qgslogger.h"
26 #include "qgsmaptopixel.h"
27 #include "qgsrectangle.h"
28 #include "qgsvectorlayer.h"
29 
31 #include "qgsvectortilelayer.h"
32 #include "qgsvectortilerenderer.h"
33 
34 
35 
37 {
38  QgsRectangle r = tm.tileExtent( id );
39  QgsPointXY p00a = mtp.transform( ct.transform( r.xMinimum(), r.yMinimum() ) );
40  QgsPointXY p11a = mtp.transform( ct.transform( r.xMaximum(), r.yMaximum() ) );
41  QgsPointXY p01a = mtp.transform( ct.transform( r.xMinimum(), r.yMaximum() ) );
42  QgsPointXY p10a = mtp.transform( ct.transform( r.xMaximum(), r.yMinimum() ) );
43  QPolygon path;
44  path << p00a.toQPointF().toPoint();
45  path << p01a.toQPointF().toPoint();
46  path << p11a.toQPointF().toPoint();
47  path << p10a.toQPointF().toPoint();
48  return path;
49 }
50 
52 {
53  QgsFields fields;
54  QStringList fieldsSorted = qgis::setToList( flds );
55  std::sort( fieldsSorted.begin(), fieldsSorted.end() );
56  for ( const QString &fieldName : std::as_const( fieldsSorted ) )
57  {
58  fields.append( QgsField( fieldName, QVariant::String ) );
59  }
60  return fields;
61 }
62 
63 double QgsVectorTileUtils::scaleToZoom( double mapScale )
64 {
65  double s0 = 559082264.0287178; // scale denominator at zoom level 0 of GoogleCRS84Quad
66  double tileZoom2 = log( s0 / mapScale ) / log( 2 );
67  tileZoom2 -= 1; // TODO: it seems that map scale is double (is that because of high-dpi screen?)
68  return tileZoom2;
69 }
70 
71 int QgsVectorTileUtils::scaleToZoomLevel( double mapScale, int sourceMinZoom, int sourceMaxZoom )
72 {
73  int tileZoom = static_cast<int>( round( scaleToZoom( mapScale ) ) );
74 
75  if ( tileZoom < sourceMinZoom )
76  tileZoom = sourceMinZoom;
77  if ( tileZoom > sourceMaxZoom )
78  tileZoom = sourceMaxZoom;
79 
80  return tileZoom;
81 }
82 
84 {
86  decoder.decode( tileID, mvt->getRawTile( tileID ) );
87  QSet<QString> fieldNames = qgis::listToSet( decoder.layerFieldNames( layerName ) );
88  fieldNames << QStringLiteral( "_geom_type" );
89  QMap<QString, QgsFields> perLayerFields;
90  QgsFields fields = QgsVectorTileUtils::makeQgisFields( fieldNames );
91  perLayerFields[layerName] = fields;
92  QgsVectorTileFeatures data = decoder.layerFeatures( perLayerFields, QgsCoordinateTransform() );
93  QgsFeatureList featuresList = data[layerName].toList();
94 
95  // turn all geometries to geom. collections (otherwise they won't be accepted by memory provider)
96  for ( int i = 0; i < featuresList.count(); ++i )
97  {
98  QgsGeometry g = featuresList[i].geometry();
100  const QgsAbstractGeometry *gg = g.constGet();
101  if ( const QgsGeometryCollection *ggc = qgsgeometry_cast<const QgsGeometryCollection *>( gg ) )
102  {
103  for ( int k = 0; k < ggc->numGeometries(); ++k )
104  gc->addGeometry( ggc->geometryN( k )->clone() );
105  }
106  else
107  gc->addGeometry( gg->clone() );
108  featuresList[i].setGeometry( QgsGeometry( gc ) );
109  }
110 
111  QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "GeometryCollection" ), layerName, QStringLiteral( "memory" ) );
112  vl->dataProvider()->addAttributes( fields.toList() );
113  vl->updateFields();
114  bool res = vl->dataProvider()->addFeatures( featuresList );
115  Q_UNUSED( res );
116  Q_ASSERT( res );
117  Q_ASSERT( featuresList.count() == vl->featureCount() );
118  vl->updateExtents();
119  QgsDebugMsgLevel( QStringLiteral( "Layer %1 features %2" ).arg( layerName ).arg( vl->featureCount() ), 2 );
120  return vl;
121 }
122 
123 
124 QString QgsVectorTileUtils::formatXYZUrlTemplate( const QString &url, QgsTileXYZ tile, const QgsTileMatrix &tileMatrix )
125 {
126  QString turl( url );
127 
128  turl.replace( QLatin1String( "{x}" ), QString::number( tile.column() ), Qt::CaseInsensitive );
129  if ( turl.contains( QLatin1String( "{-y}" ) ) )
130  {
131  turl.replace( QLatin1String( "{-y}" ), QString::number( tileMatrix.matrixHeight() - tile.row() - 1 ), Qt::CaseInsensitive );
132  }
133  else
134  {
135  turl.replace( QLatin1String( "{y}" ), QString::number( tile.row() ), Qt::CaseInsensitive );
136  }
137  turl.replace( QLatin1String( "{z}" ), QString::number( tile.zoomLevel() ), Qt::CaseInsensitive );
138  return turl;
139 }
140 
141 bool QgsVectorTileUtils::checkXYZUrlTemplate( const QString &url )
142 {
143  return url.contains( QStringLiteral( "{x}" ) ) &&
144  ( url.contains( QStringLiteral( "{y}" ) ) || url.contains( QStringLiteral( "{-y}" ) ) ) &&
145  url.contains( QStringLiteral( "{z}" ) );
146 }
147 
150 {
151  QPointF center;
152  bool operator()( const QgsTileXYZ &req1, const QgsTileXYZ &req2 )
153  {
154  QPointF p1( req1.column() + 0.5, req1.row() + 0.5 );
155  QPointF p2( req2.column() + 0.5, req2.row() + 0.5 );
156  // using chessboard distance (loading order more natural than euclidean/manhattan distance)
157  double d1 = std::max( std::fabs( center.x() - p1.x() ), std::fabs( center.y() - p1.y() ) );
158  double d2 = std::max( std::fabs( center.x() - p2.x() ), std::fabs( center.y() - p2.y() ) );
159  return d1 < d2;
160  }
161 };
162 
163 QVector<QgsTileXYZ> QgsVectorTileUtils::tilesInRange( const QgsTileRange &range, int zoomLevel )
164 {
165  QVector<QgsTileXYZ> tiles;
166  for ( int tileRow = range.startRow(); tileRow <= range.endRow(); ++tileRow )
167  {
168  for ( int tileColumn = range.startColumn(); tileColumn <= range.endColumn(); ++tileColumn )
169  {
170  tiles.append( QgsTileXYZ( tileColumn, tileRow, zoomLevel ) );
171  }
172  }
173  return tiles;
174 }
175 
176 void QgsVectorTileUtils::sortTilesByDistanceFromCenter( QVector<QgsTileXYZ> &tiles, const QPointF &center )
177 {
179  cmp.center = center;
180  std::sort( tiles.begin(), tiles.end(), cmp );
181 }
Abstract base class for all geometries.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
Class for doing transforms between two map coordinate systems.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:212
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
Geometry collection.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:90
A class to represent a 2D point.
Definition: qgspointxy.h:59
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:169
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
Definition: qgstiles.h:104
QgsRectangle tileExtent(QgsTileXYZ id) const
Returns extent of the given tile in this matrix.
Definition: qgstiles.cpp:80
int matrixHeight() const
Returns number of rows of the tile matrix.
Definition: qgstiles.h:128
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:67
int endColumn() const
Returns index of the last column in the range.
Definition: qgstiles.h:79
int endRow() const
Returns index of the last row in the range.
Definition: qgstiles.h:83
int startRow() const
Returns index of the first row in the range.
Definition: qgstiles.h:81
int startColumn() const
Returns index of the first column in the range.
Definition: qgstiles.h:77
Stores coordinates of a tile in a tile matrix set.
Definition: qgstiles.h:34
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:47
int column() const
Returns tile's column index (X)
Definition: qgstiles.h:43
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:45
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes to the provider.
Represents a vector layer which manages a vector based data sets.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
virtual void updateExtents(bool force=false)
Update the extents for the layer.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Implements a map layer that is dedicated to rendering of vector tiles.
QByteArray getRawTile(QgsTileXYZ tileID)
Fetches raw tile data for the give tile coordinates.
This class is responsible for decoding raw tile data written with Mapbox Vector Tiles encoding.
QStringList layerFieldNames(const QString &layerName) const
Returns a list of all field names in a tile. It can only be called after a successful decode()
QgsVectorTileFeatures layerFeatures(const QMap< QString, QgsFields > &perLayerFields, const QgsCoordinateTransform &ct, const QSet< QString > *layerSubset=nullptr) const
Returns decoded features grouped by sub-layers.
bool decode(QgsTileXYZ tileID, const QByteArray &rawTileData)
Tries to decode raw tile data, returns true on success.
static QgsVectorLayer * makeVectorLayerForTile(QgsVectorTileLayer *mvt, QgsTileXYZ tileID, const QString &layerName)
Returns a temporary vector layer for given sub-layer of tile in vector tile layer.
static bool checkXYZUrlTemplate(const QString &url)
Checks whether the URL template string is correct (contains {x}, {y} / {-y}, {z} placeholders)
static QString formatXYZUrlTemplate(const QString &url, QgsTileXYZ tile, const QgsTileMatrix &tileMatrix)
Returns formatted tile URL string replacing {x}, {y}, {z} placeholders (or {-y} instead of {y} for TM...
static int scaleToZoomLevel(double mapScale, int sourceMinZoom, int sourceMaxZoom)
Finds best fitting zoom level (assuming GoogleCRS84Quad tile matrix set) given map scale denominator ...
static double scaleToZoom(double mapScale)
Finds zoom level (assuming GoogleCRS84Quad tile matrix set) given map scale denominator.
static void sortTilesByDistanceFromCenter(QVector< QgsTileXYZ > &tiles, const QPointF &center)
Orders tile requests according to the distance from view center (given in tile matrix coords)
static QPolygon tilePolygon(QgsTileXYZ id, const QgsCoordinateTransform &ct, const QgsTileMatrix &tm, const QgsMapToPixel &mtp)
Returns polygon (made by four corners of the tile) in screen coordinates.
static QVector< QgsTileXYZ > tilesInRange(const QgsTileRange &range, int zoomLevel)
Returns a list of tiles in the given tile range.
static QgsFields makeQgisFields(QSet< QString > flds)
Returns QgsFields instance based on the set of field names.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:882
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QMap< QString, QVector< QgsFeature > > QgsVectorTileFeatures
Features of a vector tile, grouped by sub-layer names (key of the map)
a helper class for ordering tile requests according to the distance from view center
QPointF center
Center in tile matrix (!) coordinates.
bool operator()(const QgsTileXYZ &req1, const QgsTileXYZ &req2)