QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 : qgis::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>( floor( 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 }
qgsfields.h
qgsvectortilerenderer.h
QgsVectorTileLayer
Implements a map layer that is dedicated to rendering of vector tiles.
Definition: qgsvectortilelayer.h:84
QgsVectorLayer::updateExtents
virtual void updateExtents(bool force=false)
Update the extents for the layer.
Definition: qgsvectorlayer.cpp:801
QgsTileXYZ
Stores coordinates of a tile in a tile matrix set.
Definition: qgstiles.h:33
QgsVectorLayer::updateFields
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
Definition: qgsvectorlayer.cpp:3771
qgsrectangle.h
QgsVectorTileUtils::makeQgisFields
static QgsFields makeQgisFields(QSet< QString > flds)
Returns QgsFields instance based on the set of field names.
Definition: qgsvectortileutils.cpp:51
QgsTileRange
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:66
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsmaptopixel.h
QgsVectorTileUtils::scaleToZoom
static double scaleToZoom(double mapScale)
Finds zoom level (assuming GoogleCRS84Quad tile matrix set) given map scale denominator.
Definition: qgsvectortileutils.cpp:63
QgsTileMatrix::tileExtent
QgsRectangle tileExtent(QgsTileXYZ id) const
Returns extent of the given tile in this matrix.
Definition: qgstiles.cpp:38
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsPointXY::toQPointF
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:154
QgsFields::append
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
QgsCoordinateTransform::transform
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:239
QgsVectorLayer::featureCount
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
Definition: qgsvectorlayer.cpp:751
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsVectorTileMVTDecoder
This class is responsible for decoding raw tile data written with Mapbox Vector Tiles encoding.
Definition: qgsvectortilemvtdecoder.h:37
QgsFields::toList
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:212
QgsVectorTileMVTDecoder::layerFeatures
QgsVectorTileFeatures layerFeatures(const QMap< QString, QgsFields > &perLayerFields, const QgsCoordinateTransform &ct, const QSet< QString > *layerSubset=nullptr) const
Returns decoded features grouped by sub-layers.
Definition: qgsvectortilemvtdecoder.cpp:80
qgsvectortilelayer.h
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsTileRange::endRow
int endRow() const
Returns index of the last row in the range.
Definition: qgstiles.h:82
QgsVectorTileUtils::tilesInRange
static QVector< QgsTileXYZ > tilesInRange(const QgsTileRange &range, int zoomLevel)
Returns a list of tiles in the given tile range.
Definition: qgsvectortileutils.cpp:163
QgsGeometryCollection
Geometry collection.
Definition: qgsgeometrycollection.h:36
QgsTileMatrix
Defines a matrix of tiles for a single zoom level: it is defined by its size (width * height) and map...
Definition: qgstiles.h:103
QgsVectorTileUtils::checkXYZUrlTemplate
static bool checkXYZUrlTemplate(const QString &url)
Checks whether the URL template string is correct (contains {x}, {y} / {-y}, {z} placeholders)
Definition: qgsvectortileutils.cpp:141
QgsVectorTileMVTDecoder::layerFieldNames
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()
Definition: qgsvectortilemvtdecoder.cpp:65
LessThanTileRequest::operator()
bool operator()(const QgsTileXYZ &req1, const QgsTileXYZ &req2)
Definition: qgsvectortileutils.cpp:152
LessThanTileRequest::center
QPointF center
Center in tile matrix (!) coordinates.
Definition: qgsvectortileutils.cpp:151
QgsTileMatrix::matrixHeight
int matrixHeight() const
Returns number of rows of the tile matrix.
Definition: qgstiles.h:116
qgsvectortilemvtdecoder.h
QgsGeometryCollection::addGeometry
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsgeometrycollection.cpp:226
QgsAbstractGeometry::clone
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QgsVectorTileUtils::sortTilesByDistanceFromCenter
static void sortTilesByDistanceFromCenter(QVector< QgsTileXYZ > &tiles, const QPointF &center)
Orders tile requests according to the distance from view center (given in tile matrix coords)
Definition: qgsvectortileutils.cpp:176
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:583
qgscoordinatetransform.h
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
QgsTileRange::endColumn
int endColumn() const
Returns index of the last column in the range.
Definition: qgstiles.h:78
QgsTileXYZ::zoomLevel
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:46
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:128
QgsMapToPixel::transform
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.cpp:217
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:74
QgsVectorTileUtils::scaleToZoomLevel
static int scaleToZoomLevel(double mapScale, int sourceMinZoom, int sourceMaxZoom)
Finds best fitting zoom level (assuming GoogleCRS84Quad tile matrix set) given map scale denominator ...
Definition: qgsvectortileutils.cpp:71
qgsvectorlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsTileRange::startRow
int startRow() const
Returns index of the first row in the range.
Definition: qgstiles.h:80
QgsVectorTileUtils::makeVectorLayerForTile
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.
Definition: qgsvectortileutils.cpp:83
QgsVectorDataProvider::addFeatures
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
Definition: qgsvectordataprovider.cpp:87
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsVectorTileUtils::formatXYZUrlTemplate
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...
Definition: qgsvectortileutils.cpp:124
QgsTileXYZ::row
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:44
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
LessThanTileRequest
a helper class for ordering tile requests according to the distance from view center
Definition: qgsvectortileutils.cpp:150
QgsVectorDataProvider::addAttributes
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes to the provider.
Definition: qgsvectordataprovider.cpp:119
QgsVectorTileLayer::getRawTile
QByteArray getRawTile(QgsTileXYZ tileID)
Fetches raw tile data for the give tile coordinates.
Definition: qgsvectortilelayer.cpp:596
qgsgeometrycollection.h
QgsVectorTileFeatures
QMap< QString, QVector< QgsFeature > > QgsVectorTileFeatures
Features of a vector tile, grouped by sub-layer names (key of the map)
Definition: qgsvectortilerenderer.h:25
qgslogger.h
qgsvectortileutils.h
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsVectorTileMVTDecoder::decode
bool decode(QgsTileXYZ tileID, const QByteArray &rawTileData)
Tries to decode raw tile data, returns true on success.
Definition: qgsvectortilemvtdecoder.cpp:36
QgsVectorTileUtils::tilePolygon
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.
Definition: qgsvectortileutils.cpp:36
QgsTileRange::startColumn
int startColumn() const
Returns index of the first column in the range.
Definition: qgstiles.h:76
QgsTileXYZ::column
int column() const
Returns tile's column index (X)
Definition: qgstiles.h:42
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50