QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 
51 QgsFields QgsVectorTileUtils::makeQgisFields( const QSet<QString> &flds )
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, double z0Scale )
64 {
65  double s0 = z0Scale;
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, double z0Scale )
72 {
73  int tileZoom = static_cast<int>( round( scaleToZoom( mapScale, z0Scale ) ) );
74 
75  if ( tileZoom < sourceMinZoom )
76  tileZoom = sourceMinZoom;
77  if ( tileZoom > sourceMaxZoom )
78  tileZoom = sourceMaxZoom;
79 
80  return tileZoom;
81 }
82 
84 {
85  QgsVectorTileMVTDecoder decoder( mvt->tileMatrixSet() );
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()( QgsTileXYZ req1, 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( 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, 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:108
QgsRectangle tileExtent(QgsTileXYZ id) const
Returns extent of the given tile in this matrix.
Definition: qgstiles.cpp:81
int matrixHeight() const
Returns number of rows of the tile matrix.
Definition: qgstiles.h:160
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:71
int endColumn() const
Returns index of the last column in the range.
Definition: qgstiles.h:83
int endRow() const
Returns index of the last row in the range.
Definition: qgstiles.h:87
int startRow() const
Returns index of the first row in the range.
Definition: qgstiles.h:85
int startColumn() const
Returns index of the first column in the range.
Definition: qgstiles.h:81
Stores coordinates of a tile in a tile matrix set.
Definition: qgstiles.h:38
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:51
int column() const
Returns tile's column index (X)
Definition: qgstiles.h:47
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:49
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.
QgsVectorTileMatrixSet & tileMatrixSet()
Returns the vector tile matrix set.
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 QVector< QgsTileXYZ > tilesInRange(QgsTileRange range, int zoomLevel)
Returns a list of tiles in the given tile range.
static void sortTilesByDistanceFromCenter(QVector< QgsTileXYZ > &tiles, 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 double scaleToZoom(double mapScale, double z0Scale=559082264.0287178)
Finds zoom level given map scale denominator.
static int scaleToZoomLevel(double mapScale, int sourceMinZoom, int sourceMaxZoom, double z0Scale=559082264.0287178)
Finds the best fitting zoom level given a map scale denominator and allowed zoom level range.
static QgsFields makeQgisFields(const 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
bool operator()(QgsTileXYZ req1, QgsTileXYZ req2)
QPointF center
Center in tile matrix (!) coordinates.