QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 
64 int QgsVectorTileUtils::scaleToZoomLevel( double mapScale, int sourceMinZoom, int sourceMaxZoom )
65 {
66  double s0 = 559082264.0287178; // scale denominator at zoom level 0 of GoogleCRS84Quad
67  double tileZoom2 = log( s0 / mapScale ) / log( 2 );
68  tileZoom2 -= 1; // TODO: it seems that map scale is double (is that because of high-dpi screen?)
69  int tileZoom = static_cast<int>( round( tileZoom2 ) );
70 
71  if ( tileZoom < sourceMinZoom )
72  tileZoom = sourceMinZoom;
73  if ( tileZoom > sourceMaxZoom )
74  tileZoom = sourceMaxZoom;
75 
76  return tileZoom;
77 }
78 
80 {
82  decoder.decode( tileID, mvt->getRawTile( tileID ) );
83  QSet<QString> fieldNames = qgis::listToSet( decoder.layerFieldNames( layerName ) );
84  fieldNames << QStringLiteral( "_geom_type" );
85  QMap<QString, QgsFields> perLayerFields;
86  QgsFields fields = QgsVectorTileUtils::makeQgisFields( fieldNames );
87  perLayerFields[layerName] = fields;
88  QgsVectorTileFeatures data = decoder.layerFeatures( perLayerFields, QgsCoordinateTransform() );
89  QgsFeatureList featuresList = data[layerName].toList();
90 
91  // turn all geometries to geom. collections (otherwise they won't be accepted by memory provider)
92  for ( int i = 0; i < featuresList.count(); ++i )
93  {
94  QgsGeometry g = featuresList[i].geometry();
96  const QgsAbstractGeometry *gg = g.constGet();
97  if ( const QgsGeometryCollection *ggc = qgsgeometry_cast<const QgsGeometryCollection *>( gg ) )
98  {
99  for ( int k = 0; k < ggc->numGeometries(); ++k )
100  gc->addGeometry( ggc->geometryN( k )->clone() );
101  }
102  else
103  gc->addGeometry( gg->clone() );
104  featuresList[i].setGeometry( QgsGeometry( gc ) );
105  }
106 
107  QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "GeometryCollection" ), layerName, QStringLiteral( "memory" ) );
108  vl->dataProvider()->addAttributes( fields.toList() );
109  vl->updateFields();
110  bool res = vl->dataProvider()->addFeatures( featuresList );
111  Q_ASSERT( res );
112  Q_ASSERT( featuresList.count() == vl->featureCount() );
113  vl->updateExtents();
114  QgsDebugMsgLevel( QStringLiteral( "Layer %1 features %2" ).arg( layerName ).arg( vl->featureCount() ), 2 );
115  return vl;
116 }
117 
118 
119 QString QgsVectorTileUtils::formatXYZUrlTemplate( const QString &url, QgsTileXYZ tile, const QgsTileMatrix &tileMatrix )
120 {
121  QString turl( url );
122 
123  turl.replace( QLatin1String( "{x}" ), QString::number( tile.column() ), Qt::CaseInsensitive );
124  if ( turl.contains( QLatin1String( "{-y}" ) ) )
125  {
126  turl.replace( QLatin1String( "{-y}" ), QString::number( tileMatrix.matrixHeight() - tile.row() - 1 ), Qt::CaseInsensitive );
127  }
128  else
129  {
130  turl.replace( QLatin1String( "{y}" ), QString::number( tile.row() ), Qt::CaseInsensitive );
131  }
132  turl.replace( QLatin1String( "{z}" ), QString::number( tile.zoomLevel() ), Qt::CaseInsensitive );
133  return turl;
134 }
135 
136 bool QgsVectorTileUtils::checkXYZUrlTemplate( const QString &url )
137 {
138  return url.contains( QStringLiteral( "{x}" ) ) &&
139  ( url.contains( QStringLiteral( "{y}" ) ) || url.contains( QStringLiteral( "{-y}" ) ) ) &&
140  url.contains( QStringLiteral( "{z}" ) );
141 }
142 
145 {
146  QPointF center;
147  bool operator()( const QgsTileXYZ &req1, const QgsTileXYZ &req2 )
148  {
149  QPointF p1( req1.column() + 0.5, req1.row() + 0.5 );
150  QPointF p2( req2.column() + 0.5, req2.row() + 0.5 );
151  // using chessboard distance (loading order more natural than euclidean/manhattan distance)
152  double d1 = std::max( std::fabs( center.x() - p1.x() ), std::fabs( center.y() - p1.y() ) );
153  double d2 = std::max( std::fabs( center.x() - p2.x() ), std::fabs( center.y() - p2.y() ) );
154  return d1 < d2;
155  }
156 };
157 
158 QVector<QgsTileXYZ> QgsVectorTileUtils::tilesInRange( const QgsTileRange &range, int zoomLevel )
159 {
160  QVector<QgsTileXYZ> tiles;
161  for ( int tileRow = range.startRow(); tileRow <= range.endRow(); ++tileRow )
162  {
163  for ( int tileColumn = range.startColumn(); tileColumn <= range.endColumn(); ++tileColumn )
164  {
165  tiles.append( QgsTileXYZ( tileColumn, tileRow, zoomLevel ) );
166  }
167  }
168  return tiles;
169 }
170 
171 void QgsVectorTileUtils::sortTilesByDistanceFromCenter( QVector<QgsTileXYZ> &tiles, const QPointF &center )
172 {
174  cmp.center = center;
175  std::sort( tiles.begin(), tiles.end(), cmp );
176 }
qgsfields.h
qgsvectortilerenderer.h
QgsVectorTileLayer
Definition: qgsvectortilelayer.h:83
QgsVectorLayer::updateExtents
virtual void updateExtents(bool force=false)
Update the extents for the layer.
Definition: qgsvectorlayer.cpp:801
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
QgsTileXYZ
Definition: qgstiles.h:32
QgsVectorLayer::updateFields
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
Definition: qgsvectorlayer.cpp:3763
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
Definition: qgstiles.h:65
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsmaptopixel.h
QgsTileMatrix::tileExtent
QgsRectangle tileExtent(QgsTileXYZ id) const
Returns extent of the given tile in this matrix.
Definition: qgstiles.cpp:38
QgsRectangle::xMaximum
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsFields
Definition: qgsfields.h:44
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
Definition: qgsrectangle.h:41
QgsVectorTileMVTDecoder
Definition: qgsvectortilemvtdecoder.h:36
QgsFields::toList
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:212
qgsvectortilelayer.h
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:158
QgsGeometryCollection
Geometry collection.
Definition: qgsgeometrycollection.h:35
QgsTileMatrix
Definition: qgstiles.h:102
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:136
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:147
LessThanTileRequest::center
QPointF center
Center in tile matrix (!) coordinates.
Definition: qgsvectortileutils.cpp:146
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:171
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:572
qgscoordinatetransform.h
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:128
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:59
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:71
QgsRectangle::yMaximum
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
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:64
qgsvectorlayer.h
QgsPointXY
Definition: qgspointxy.h:43
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:79
QgsVectorDataProvider::addFeatures
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
Definition: qgsvectordataprovider.cpp:85
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:119
QgsVectorTileMVTDecoder::layerFeatures
QgsVectorTileFeatures layerFeatures(const QMap< QString, QgsFields > &perLayerFields, const QgsCoordinateTransform &ct) const
Returns decoded features grouped by sub-layers. It can only be called after a successful decode()
Definition: qgsvectortilemvtdecoder.cpp:80
QgsTileXYZ::row
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:57
QgsGeometry
Definition: qgsgeometry.h:122
QgsMapToPixel
Definition: qgsmaptopixel.h:37
QgsVectorLayer
Definition: qgsvectorlayer.h:385
LessThanTileRequest
a helper class for ordering tile requests according to the distance from view center
Definition: qgsvectortileutils.cpp:144
QgsVectorDataProvider::addAttributes
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes to the provider.
Definition: qgsvectordataprovider.cpp:112
QgsRectangle::yMinimum
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsVectorTileLayer::getRawTile
QByteArray getRawTile(QgsTileXYZ tileID)
Fetches raw tile data for the give tile coordinates.
Definition: qgsvectortilelayer.cpp:289
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
Definition: qgscoordinatetransform.h:52
QgsVectorTileMVTDecoder::decode
bool decode(QgsTileXYZ tileID, const QByteArray &rawTileData)
Tries to decode raw tile data, returns true on success.
Definition: qgsvectortilemvtdecoder.cpp:36
QgsRectangle::xMinimum
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
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:55
QgsField
Definition: qgsfield.h:49