25using namespace Qt::StringLiterals;
29 constexpr double z0xMin = -20037508.3427892;
30 constexpr double z0yMax = 20037508.3427892;
38 double z0xMin = z0TopLeftPoint.
x();
39 double z0yMax = z0TopLeftPoint.
y();
40 double z0xMax = z0xMin + z0MatrixWidth * z0Dimension;
41 double z0yMin = z0yMax - z0MatrixHeight * z0Dimension;
44 constexpr double TILE_SIZE = 256.0;
45 constexpr double PIXELS_TO_M = 2.8 / 10000.0;
48 const double scaleDenom0 = ( z0Dimension / TILE_SIZE ) * ( unitToMeters / PIXELS_TO_M );
50 int numTiles =
static_cast<int>( pow( 2,
zoomLevel ) );
55 tm.mMatrixWidth = z0MatrixWidth * numTiles;
56 tm.mMatrixHeight = z0MatrixHeight * numTiles;
57 tm.mTileXSpan = ( z0xMax - z0xMin ) / tm.mMatrixWidth;
58 tm.mTileYSpan = ( z0yMax - z0yMin ) / tm.mMatrixHeight;
59 tm.mExtent =
QgsRectangle( z0xMin, z0yMin, z0xMax, z0yMax );
60 tm.mScaleDenom = scaleDenom0 / pow( 2,
zoomLevel );
67 int numTiles =
static_cast<int>( pow( 2,
zoomLevel ) );
69 int aNumTiles =
static_cast<int>( pow( 2, aZoomLevel ) );
73 tm.mCrs = tileMatrix.
crs();
75 tm.mMatrixWidth = aMatrixWidth * numTiles / aNumTiles;
76 tm.mMatrixHeight = aMatrixHeight * numTiles / aNumTiles;
77 tm.mTileXSpan = aExtent.
width() / tm.mMatrixWidth;
78 tm.mTileYSpan = aExtent.
height() / tm.mMatrixHeight;
80 tm.mScaleDenom = tileMatrix.
scale() * pow( 2, aZoomLevel ) / pow( 2,
zoomLevel );
86 const long long zoomFactor = 1LL << (
zoomLevel - mZoomLevel );
87 return mMatrixWidth * zoomFactor;
92 const long long zoomFactor = 1LL << (
zoomLevel - mZoomLevel );
93 return mMatrixHeight * zoomFactor;
98 double xMin = mExtent.
xMinimum() + mTileXSpan *
id.column();
99 double xMax = xMin + mTileXSpan;
100 double yMax = mExtent.yMaximum() - mTileYSpan *
id.row();
101 double yMin = yMax - mTileYSpan;
107 double x = mExtent.xMinimum() + mTileXSpan *
id.column() + mTileXSpan / 2;
108 double y = mExtent.yMaximum() - mTileYSpan *
id.row() - mTileYSpan / 2;
114 double x0 = std::clamp( r.
xMinimum(), mExtent.xMinimum(), mExtent.xMaximum() );
115 double y0 = std::clamp( r.
yMinimum(), mExtent.yMinimum(), mExtent.yMaximum() );
116 double x1 = std::clamp( r.
xMaximum(), mExtent.xMinimum(), mExtent.xMaximum() );
117 double y1 = std::clamp( r.
yMaximum(), mExtent.yMinimum(), mExtent.yMaximum() );
118 if ( x0 >= x1 || y0 >= y1 )
121 double tileX1 = ( x0 - mExtent.xMinimum() ) / mTileXSpan;
122 double tileX2 = ( x1 - mExtent.xMinimum() ) / mTileXSpan;
123 double tileY1 = ( mExtent.yMaximum() - y1 ) / mTileYSpan;
124 double tileY2 = ( mExtent.yMaximum() - y0 ) / mTileYSpan;
126 QgsDebugMsgLevel( u
"Tile range of edges [%1,%2] - [%3,%4]"_s.arg( tileX1 ).arg( tileY1 ).arg( tileX2 ).arg( tileY2 ), 2 );
129 int startColumn = std::clamp(
static_cast<int>( floor( tileX1 ) ), 0, mMatrixWidth - 1 );
130 int endColumn = std::clamp(
static_cast<int>( floor( tileX2 ) ), 0, mMatrixWidth - 1 );
131 int startRow = std::clamp(
static_cast<int>( floor( tileY1 ) ), 0, mMatrixHeight - 1 );
132 int endRow = std::clamp(
static_cast<int>( floor( tileY2 ) ), 0, mMatrixHeight - 1 );
133 return QgsTileRange( startColumn, endColumn, startRow, endRow );
138 double dx = mapPoint.
x() - mExtent.xMinimum();
139 double dy = mExtent.yMaximum() - mapPoint.
y();
140 return QPointF( dx / mTileXSpan, dy / mTileYSpan );
199 if ( res == -1 || it->zoomLevel() < res )
200 res = it->zoomLevel();
210 if ( res == -1 || it->zoomLevel() > res )
211 res = it->zoomLevel();
248 double scaleUnder = 0;
249 double scaleOver = 0;
266 if ( it->scale() > scale && ( zoomUnder == -1 || zoomUnder < it->zoomLevel() ) )
268 zoomUnder = it->zoomLevel();
269 scaleUnder = it->scale();
271 if ( it->scale() < scale && ( zoomOver == -1 || zoomOver > it->zoomLevel() ) )
273 zoomOver = it->zoomLevel();
274 scaleOver = it->scale();
287 if ( scaleOver < scale && scale < scaleUnder )
289 return ( scaleUnder - scale ) / ( scaleUnder - scaleOver ) * ( zoomOver - zoomUnder ) + zoomUnder;
291 scaleUnder = scaleOver;
292 zoomUnder = zoomOver;
293 scaleOver = scaleOver / 2;
298 return ( scaleUnder - scale ) / ( scaleUnder - scaleOver ) * ( zoomOver - zoomUnder ) + zoomUnder;
307 tileZoom =
static_cast<int>( round(
scaleToZoom( scale ) ) );
310 tileZoom =
static_cast<int>( floor(
scaleToZoom( scale ) ) );
328 return actualMapScale;
335 constexpr double METERS_PER_DEGREE = M_PI / 180.0 * 6378137;
336 constexpr double INCHES_PER_METER = 39.370078;
337 const double mapWidthInches = mapExtent.
width() * METERS_PER_DEGREE * INCHES_PER_METER;
339 double scale = mapWidthInches * mapDpi /
static_cast< double >( mapSize.width() );
350 return actualMapScale;
362 auto readMatrixFromElement = [](
const QDomElement &matrixElement ) ->
QgsTileMatrix {
364 matrix.mZoomLevel = matrixElement.attribute( u
"zoomLevel"_s ).toInt();
365 matrix.mMatrixWidth = matrixElement.attribute( u
"matrixWidth"_s ).toInt();
366 matrix.mMatrixHeight = matrixElement.attribute( u
"matrixHeight"_s ).toInt();
368 matrixElement.attribute( u
"xMin"_s ).toDouble(), matrixElement.attribute( u
"yMin"_s ).toDouble(), matrixElement.attribute( u
"xMax"_s ).toDouble(), matrixElement.attribute( u
"yMax"_s ).toDouble()
371 matrix.mScaleDenom = matrixElement.attribute( u
"scale"_s ).toDouble();
372 matrix.mTileXSpan = matrixElement.attribute( u
"tileXSpan"_s ).toDouble();
373 matrix.mTileYSpan = matrixElement.attribute( u
"tileYSpan"_s ).toDouble();
374 matrix.mCrs.
readXml( matrixElement );
378 const QDomNodeList children = element.childNodes();
379 for (
int i = 0; i < children.size(); i++ )
381 const QDomElement matrixElement = children.at( i ).toElement();
382 if ( matrixElement.tagName() ==
"rootMatrix"_L1 )
385 QgsTileMatrix matrix = readMatrixFromElement( matrixElement );
392 const QDomElement rootElement = element.firstChildElement( u
"rootMatrix"_s );
393 if ( !rootElement.isNull() )
395 mRootMatrix = readMatrixFromElement( rootElement );
403 QDomElement setElement = document.createElement( u
"matrixSet"_s );
406 auto writeMatrixToElement = [&document](
const QgsTileMatrix &matrix, QDomElement &matrixElement ) {
407 matrixElement.setAttribute( u
"zoomLevel"_s, matrix.
zoomLevel() );
408 matrixElement.setAttribute( u
"matrixWidth"_s, matrix.
matrixWidth() );
409 matrixElement.setAttribute( u
"matrixHeight"_s, matrix.
matrixHeight() );
417 matrixElement.setAttribute( u
"tileXSpan"_s,
qgsDoubleToString( matrix.mTileXSpan ) );
418 matrixElement.setAttribute( u
"tileYSpan"_s,
qgsDoubleToString( matrix.mTileYSpan ) );
425 QDomElement matrixElement = document.createElement( u
"matrix"_s );
426 writeMatrixToElement( *it, matrixElement );
427 setElement.appendChild( matrixElement );
430 QDomElement rootElement = document.createElement( u
"rootMatrix"_s );
432 setElement.appendChild( rootElement );
439 QVector<QgsTileXYZ> tiles;
442 for (
int tileRow = range.
startRow(); tileRow <= range.
endRow(); ++tileRow )
446 QgsTileXYZ tile( tileColumn, tileRow, zoomLevel );
456 if ( !tiles.contains( replacement ) )
457 tiles.append( replacement );
@ Esri
No scale doubling, always rounds down when matching to available tile levels.
@ MapBox
Uses a scale doubling approach to account for hi-DPI tiles, and rounds to the nearest tile level for ...
TileAvailability
Possible availability states for a tile within a tile matrix.
@ UseLowerZoomLevelTile
Tile is not available at the requested zoom level, it should be replaced by a tile from a lower zoom ...
@ NotAvailable
Tile is not available within the matrix, e.g. there is no content for the tile.
@ AvailableNoChildren
Tile is available within the matrix, and is known to have no children (ie no higher zoom level tiles ...
@ Available
Tile is available within the matrix.
Represents a coordinate reference system (CRS).
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
double rendererScale() const
Returns the renderer map scale.
QSize outputSize() const
Returns the size of the resulting rendered image, in pixels.
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
virtual QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Writes the set to an XML element.
Qgis::ScaleToTileZoomLevelMethod mScaleToTileZoomMethod
void addGoogleCrs84QuadTiles(int minimumZoom=0, int maximumZoom=14)
Adds tile matrices corresponding to the standard web mercator/GoogleCRS84Quad setup.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system associated with the tiles.
std::function< Qgis::TileAvailability(QgsTileXYZ id) > mTileAvailabilityFunction
double scaleForRenderContext(const QgsRenderContext &context) const
Calculates the correct scale to use for the tiles when rendered using the specified render context.
int minimumZoom() const
Returns the minimum zoom level for tiles present in the set.
double scaleToZoom(double scale) const
Calculates a fractional zoom level given a map scale denominator.
QMap< int, QgsTileMatrix > mTileMatrices
QVector< QgsTileXYZ > tilesInRange(QgsTileRange range, int zoomLevel) const
Returns a list of tiles in the given tile range.
int maximumZoom() const
Returns the maximum zoom level for tiles present in the set.
QgsTileMatrix tileMatrix(int zoom) const
Returns the tile matrix corresponding to the specified zoom.
Qgis::TileAvailability tileAvailability(QgsTileXYZ id) const
Returns the availability of the given tile in this matrix.
QgsTileMatrix rootMatrix() const
Returns the root tile matrix (usually corresponding to zoom level 0).
virtual bool readXml(const QDomElement &element, QgsReadWriteContext &context)
Reads the set from an XML element.
void addMatrix(const QgsTileMatrix &matrix)
Adds a matrix to the set.
double calculateTileScaleForMap(double actualMapScale, const QgsCoordinateReferenceSystem &mapCrs, const QgsRectangle &mapExtent, const QSize mapSize, const double mapDpi) const
Calculates the correct scale to use for the tiles when rendered using the specified map properties.
void dropMatricesOutsideZoomRange(int minimumZoom, int maximumZoom)
Deletes any existing matrices which fall outside the zoom range specified by minimumZoom to maximumZo...
bool isEmpty() const
Returns true if the matrix set is empty.
QgsTileMatrix mRootMatrix
void setRootMatrix(const QgsTileMatrix &matrix)
Sets the root tile matrix (usually corresponding to zoom level 0).
std::function< Qgis::TileAvailability(QgsTileXYZ id, QgsTileXYZ &replacement) > mTileReplacementFunction
int scaleToZoomLevel(double scale, bool clamp=true) const
Finds the best fitting (integer) zoom level given a map scale denominator.
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
QgsRectangle tileExtent(QgsTileXYZ id) const
Returns extent of the given tile in this matrix.
QPointF mapToTileCoordinates(const QgsPointXY &mapPoint) const
Returns row/column coordinates (floating point number) from the given point in map coordinates.
QgsTileRange tileRangeFromExtent(const QgsRectangle &mExtent) const
Returns tile range that fully covers the given extent.
static QgsTileMatrix fromWebMercator(int zoomLevel)
Returns a tile matrix for the usual web mercator.
QgsRectangle extent() const
Returns extent of the tile matrix.
int matrixWidth() const
Returns number of columns of the tile matrix.
QgsCoordinateReferenceSystem crs() const
Returns the crs of the tile matrix.
double scale() const
Returns scale denominator of the tile matrix.
long long derivedMatrixHeightAtZoomLevel(int zoomLevel) const
Returns the calculated matrix height at the specified zoom level.
QgsPointXY tileCenter(QgsTileXYZ id) const
Returns center of the given tile in this matrix.
int matrixHeight() const
Returns number of rows of the tile matrix.
static QgsTileMatrix fromTileMatrix(int zoomLevel, const QgsTileMatrix &tileMatrix)
Returns a tile matrix based on another one.
long long derivedMatrixWidthAtZoomLevel(int zoomLevel) const
Returns the calculated matrix width at the specified zoom level.
int zoomLevel() const
Returns the zoom level of the tile matrix.
static QgsTileMatrix fromCustomDef(int zoomLevel, const QgsCoordinateReferenceSystem &crs, const QgsPointXY &z0TopLeftPoint, double z0Dimension, int z0MatrixWidth=1, int z0MatrixHeight=1)
Returns a tile matrix for a specific CRS, top left point, zoom level 0 dimension in CRS units.
A range of tiles in a tile matrix.
int endColumn() const
Returns index of the last column in the range.
int endRow() const
Returns index of the last row in the range.
int startRow() const
Returns index of the first row in the range.
int startColumn() const
Returns index of the first column in the range.
Stores coordinates of a tile in a tile matrix set.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define BUILTIN_UNREACHABLE
#define QgsDebugMsgLevel(str, level)