39#include <QWaitCondition>
41using namespace Qt::StringLiterals;
48 int tile2tms(
const int y,
const int zoom )
50 double n = std::pow( 2, zoom );
51 return (
int ) std::floor( n - y - 1 );
55void MetaTile::addTile(
const int row,
const int col, Tile tileToAdd,
const QgsRectangle &extent )
57 tiles.insert( QPair<int, int>( row, col ), tileToAdd );
66 mExtent.combineExtentWith( extent );
72 QList<MetaTile> getMetatiles(
73 const QgsTileMatrix &z0Matrix,
const QgsRectangle &contentsExtent,
int zoom,
long long &tileCount,
int metaTileSize,
const QList<QgsTileExtentMaxZoomRegion> &maxZoomRegions,
int defaultMaxZoom
78 const long long matrixWidth = targetZoomMatrix.
matrixWidth();
79 const long long matrixHeight = targetZoomMatrix.
matrixHeight();
82 const double tileWidthUnits = tileMatrixSetExtent.
width() / matrixWidth;
83 const double tileHeightUnits = tileMatrixSetExtent.
height() / matrixHeight;
85 int minX =
static_cast<int>( std::floor( ( contentsExtent.
xMinimum() - tileMatrixSetExtent.
xMinimum() ) / tileWidthUnits ) );
86 int maxX =
static_cast<int>( std::ceil( ( contentsExtent.
xMaximum() - tileMatrixSetExtent.
xMinimum() ) / tileWidthUnits ) - 1 );
87 int minY =
static_cast<int>( std::floor( ( tileMatrixSetExtent.
yMaximum() - contentsExtent.
yMaximum() ) / tileHeightUnits ) );
88 int maxY =
static_cast<int>( std::ceil( ( tileMatrixSetExtent.
yMaximum() - contentsExtent.
yMinimum() ) / tileHeightUnits ) - 1 );
90 minX = std::clamp<int>( minX, 0,
static_cast<int>( matrixWidth - 1 ) );
91 maxX = std::clamp<int>( maxX, 0,
static_cast<int>( matrixWidth - 1 ) );
92 minY = std::clamp<int>( minY, 0,
static_cast<int>( matrixHeight - 1 ) );
93 maxY = std::clamp<int>( maxY, 0,
static_cast<int>( matrixHeight - 1 ) );
96 const int totalMetaColumns =
static_cast<int>( std::ceil(
static_cast<double>( maxX - minX + 1 ) / metaTileSize ) );
97 const int totalMetaRows =
static_cast<int>( std::ceil(
static_cast<double>( maxY - minY + 1 ) / metaTileSize ) );
99 QList<MetaTile> metaTiles;
100 for (
int metaTileColumn = 0; metaTileColumn < totalMetaColumns; ++metaTileColumn )
102 const int startI = metaTileColumn * metaTileSize;
103 const int endI = std::min( startI + metaTileSize - 1, maxX - minX );
104 const int startX = minX + startI;
105 const int endX = minX + endI;
107 for (
int metaTileRow = 0; metaTileRow < totalMetaRows; ++metaTileRow )
109 const int startJ = metaTileRow * metaTileSize;
110 const int endJ = std::min( startJ + metaTileSize - 1, maxY - minY );
111 const int startY = minY + startJ;
112 const int endY = minY + endJ;
114 const double metaTileMinX = tileMatrixSetExtent.
xMinimum() + startX * tileWidthUnits;
115 const double metaTileMaxX = tileMatrixSetExtent.
xMinimum() + ( endX + 1 ) * tileWidthUnits;
116 const double metaTileMaxY = tileMatrixSetExtent.
yMaximum() - startY * tileHeightUnits;
117 const double metaTileMinY = tileMatrixSetExtent.
yMaximum() - ( endY + 1 ) * tileHeightUnits;
118 const QgsRectangle metaTileExtent( metaTileMinX, metaTileMaxY, metaTileMaxX, metaTileMinY );
121 if ( !maxZoomRegions.isEmpty() )
125 if ( metaTileMaxZoom < zoom )
134 for (
int x = startX, i = startI; x <= endX; ++x, ++i )
136 for (
int y = startY, j = startJ; y <= endY; ++y, ++j )
138 const double tileMinX = tileMatrixSetExtent.
xMinimum() + x * tileWidthUnits;
139 const double tileMaxX = tileMinX + tileWidthUnits;
140 const double tileMaxY = tileMatrixSetExtent.
yMaximum() - y * tileHeightUnits;
141 const double tileMinY = tileMaxY - tileHeightUnits;
143 const QgsRectangle tileExtent( tileMinX, tileMinY, tileMaxX, tileMaxY );
145 metaTile.addTile( i % metaTileSize, j % metaTileSize, Tile( x, y, zoom ), tileExtent );
150 if ( !metaTile.tiles.isEmpty() )
152 metaTiles.append( metaTile );
170template<
typename T>
class PendingTilesToWriteQueue
176 void push(
const QList<T> &tiles )
178 if ( tiles.isEmpty() )
181 QMutexLocker locker( &mMutex );
182 for (
const T &tile : tiles )
184 mQueue.enqueue( tile );
196 bool popBatch( QList<T> &batch,
int maxBatchSize,
unsigned long timeoutMs = 500 )
198 QMutexLocker locker( &mMutex );
201 while ( mQueue.isEmpty() && !mFinished )
203 mNotEmpty.wait( &mMutex );
206 if ( mQueue.isEmpty() )
210 while ( mQueue.size() < maxBatchSize && !mFinished )
212 if ( !mNotEmpty.wait( &mMutex, timeoutMs ) )
219 while ( !mQueue.isEmpty() && batch.size() < maxBatchSize )
221 batch.append( mQueue.dequeue() );
231 QMutexLocker locker( &mMutex );
238 mutable QMutex mMutex;
239 QWaitCondition mNotEmpty;
240 bool mFinished =
false;
247QString QgsXyzTilesBaseAlgorithm::group()
const
249 return QObject::tr(
"Raster tools" );
252QString QgsXyzTilesBaseAlgorithm::groupId()
const
254 return u
"rastertools"_s;
262void QgsXyzTilesBaseAlgorithm::createCommonParameters()
264 auto extentParam = std::make_unique<QgsProcessingParameterExtent>( u
"EXTENT"_s, QObject::tr(
"Extent" ) );
265 extentParam->setHelp( QObject::tr(
"Spatial extent of the area for tile generation." ) );
266 addParameter( extentParam.release() );
269 minZoomParam->setHelp(
271 "Minimum zoom level for generated tiles (0–25). Lower zoom levels cover broader geographic areas "
272 "at lower spatial resolution. Must be less than or equal to the maximum zoom level."
275 addParameter( minZoomParam.release() );
278 maxZoomParam->setHelp(
280 "Maximum zoom level for generated tiles (0–25). Higher zoom levels capture finer map details "
281 "and higher resolution, but exponentially increase total tile count, storage requirements, and rendering time. "
282 "Must be greater than or equal to the minimum zoom level."
285 addParameter( maxZoomParam.release() );
288 dpiParam->setHelp( QObject::tr(
"Output resolution in DPI for rendered map content." ) );
290 addParameter( dpiParam.release() );
292 auto bgColorParam = std::make_unique<QgsProcessingParameterColor>( u
"BACKGROUND_COLOR"_s, QObject::tr(
"Background color" ), QColor( Qt::transparent ),
true,
true );
293 bgColorParam->setHelp( QObject::tr(
"Background color used when rendering map tiles." ) );
294 addParameter( bgColorParam.release() );
296 auto antialiasParam = std::make_unique<QgsProcessingParameterBoolean>( u
"ANTIALIAS"_s, QObject::tr(
"Enable antialiasing" ),
true );
297 antialiasParam->setHelp( QObject::tr(
"Controls whether antialiasing is applied during tile rendering." ) );
299 addParameter( antialiasParam.release() );
301 auto tileFormatParam = std::make_unique<QgsProcessingParameterEnum>( u
"TILE_FORMAT"_s, QObject::tr(
"Tile format" ), QStringList { u
"PNG"_s, u
"JPG"_s, u
"WEBP"_s },
false, 0 );
302 tileFormatParam->setHelp( QObject::tr(
"Output image format for the rendered tiles." ) );
303 addParameter( tileFormatParam.release() );
306 qualityParam->setHelp( QObject::tr(
"Image quality percentage used when tile format is set to JPG (1–100)." ) );
308 addParameter( qualityParam.release() );
311 metaTileSizeParam->setHelp( QObject::tr(
"Size of metatiles (in tile units) used during rendering." ) );
313 addParameter( metaTileSizeParam.release() );
315 auto skipEmptyTilesParam = std::make_unique<QgsProcessingParameterBoolean>( u
"SKIP_EMPTY_TILES"_s, QObject::tr(
"Skip empty tiles" ),
false );
316 skipEmptyTilesParam->setHelp( QObject::tr(
"If set, completely empty tiles will be skipped." ) );
318 addParameter( skipEmptyTilesParam.release() );
320 auto tileExtentMaxZoomParam = std::make_unique<QgsProcessingParameterTileExtentMaxZoomList>( u
"TILE_MAX_ZOOM_EXTENTS"_s, QObject::tr(
"Maximum zoom extents" ), QVariant(),
true );
321 tileExtentMaxZoomParam->setHelp( QObject::tr(
"Allows overriding the maximum zoom level for specific geographic regions, so that more detailed tiles can be created for important areas." ) );
323 addParameter( tileExtentMaxZoomParam.release() );
326void QgsXyzTilesBaseAlgorithm::createTileMatrixParameters()
328 auto crsParam = std::make_unique<QgsProcessingParameterCrs>( u
"TARGET_CRS"_s, QObject::tr(
"Target CRS" ), QVariant( u
"EPSG:3857"_s ) );
330 crsParam->setHelp( QObject::tr(
"Coordinate reference system used for the output tile matrix set." ) );
331 addParameter( crsParam.release() );
333 auto z0ExtentParam = std::make_unique<QgsProcessingParameterExtent>( u
"Z0_EXTENT"_s, QObject::tr(
"Zoom 0 extent" ) );
335 z0ExtentParam->setHelp(
337 "Extent of zoom level 0 in target CRS coordinates. Required when target CRS is not EPSG:3857. If the target CRS is EPSG:3857 then this parameter will be ignored and a standard Web Mercator "
338 "tile matrix will be used instead."
341 addParameter( z0ExtentParam.release() );
345 z0WidthParam->setHelp( QObject::tr(
"Number of tile columns at zoom level 0 (matrix width)." ) );
346 addParameter( z0WidthParam.release() );
350 z0HeightParam->setHelp( QObject::tr(
"Number of tile rows at zoom level 0 (matrix height)." ) );
351 addParameter( z0HeightParam.release() );
356 Q_UNUSED( feedback );
363 QSet<QString> visibleLayers;
366 if ( layer->isVisible() )
368 visibleLayers << layer->layer()->id();
375 if ( visibleLayers.contains( layer->id() ) )
378 clonedLayer->moveToThread(
nullptr );
379 mLayers << clonedLayer;
383 if ( parameters.contains( u
"TILE_WIDTH"_s ) )
385 mTileWidth = parameterAsInt( parameters, u
"TILE_WIDTH"_s, context );
388 if ( parameters.contains( u
"TILE_HEIGHT"_s ) )
390 mTileHeight = parameterAsInt( parameters, u
"TILE_HEIGHT"_s, context );
393 if ( parameters.contains( u
"TARGET_CRS"_s ) )
395 mTargetCrs = parameterAsCrs( parameters, u
"TARGET_CRS"_s, context );
402 int z0MatrixWidth = 1;
403 if ( parameters.contains( u
"Z0_MATRIX_WIDTH"_s ) )
405 z0MatrixWidth = parameterAsInt( parameters, u
"Z0_MATRIX_WIDTH"_s, context );
408 int z0MatrixHeight = 1;
409 if ( parameters.contains( u
"Z0_MATRIX_HEIGHT"_s ) )
411 z0MatrixHeight = parameterAsInt( parameters, u
"Z0_MATRIX_HEIGHT"_s, context );
414 mTileGenerationRegion = parameterAsExtent( parameters, u
"EXTENT"_s, context, mTargetCrs );
416 const QgsRectangle userZ0Extent = parameterAsExtent( parameters, u
"Z0_EXTENT"_s, context, mTargetCrs );
418 if ( mTargetCrs.authid() ==
"EPSG:3857"_L1 )
422 feedback->
pushWarning( QObject::tr(
"Tiles are being generated in EPSG:3857, so a standard Web Mercator tile matrix will be used. The manual zoom 0 extent will be ignored." ) );
424 z0Extent =
QgsRectangle( -MERC_MAX, -MERC_MAX, MERC_MAX, MERC_MAX );
430 throw QgsProcessingException( QObject::tr(
"Zoom 0 extent must be specified when using a custom target CRS (%1)" ).arg( mTargetCrs.userFriendlyIdentifier() ) );
432 z0Extent = userZ0Extent;
433 const double rawPixelXSize = z0Extent.
width() / (
static_cast<double>( z0MatrixWidth ) * mTileWidth );
434 const double rawPixelYSize = z0Extent.
height() / (
static_cast<double>( z0MatrixHeight ) * mTileHeight );
439 const double isotropicPixelSize = std::max( rawPixelXSize, rawPixelYSize );
440 const double requiredWidth = isotropicPixelSize * z0MatrixWidth * mTileWidth;
441 const double requiredHeight = isotropicPixelSize * z0MatrixHeight * mTileHeight;
444 z0Extent =
QgsRectangle( center.
x() - requiredWidth / 2.0, center.
y() - requiredHeight / 2.0, center.
x() + requiredWidth / 2.0, center.
y() + requiredHeight / 2.0 );
461 mMinZoom = parameterAsInt( parameters, u
"ZOOM_MIN"_s, context );
462 mMaxZoom = parameterAsInt( parameters, u
"ZOOM_MAX"_s, context );
463 if ( mMaxZoom < mMinZoom )
465 throw QgsProcessingException( QObject::tr(
"Maximum zoom (%1) must be ≥ minimum zoom (%2)" ).arg( mMaxZoom ).arg( mMinZoom ) );
468 mMaxZoomLimitIncludingOverrides = mMaxZoom;
469 const QList<QgsTileExtentMaxZoomRegion> rawRegions
470 = qgis::down_cast< const QgsProcessingParameterTileExtentMaxZoomList *>( parameterDefinition( u
"TILE_MAX_ZOOM_EXTENTS"_s ) )->parameterAsRegionList( parameters.value( u
"TILE_MAX_ZOOM_EXTENTS"_s ), context );
471 if ( !rawRegions.isEmpty() )
480 ct.setBallparkTransformsAreAppropriate(
true );
482 mMaxZoomRegions.append( targetRegion );
483 mMaxZoomLimitIncludingOverrides = std::max( mMaxZoomLimitIncludingOverrides, region.maxZoom );
492 mDpi = parameterAsInt( parameters, u
"DPI"_s, context );
493 mBackgroundColor = parameterAsColor( parameters, u
"BACKGROUND_COLOR"_s, context );
494 mAntialias = parameterAsBool( parameters, u
"ANTIALIAS"_s, context );
495 mSkipEmptyTiles = parameterAsBool( parameters, u
"SKIP_EMPTY_TILES"_s, context );
496 switch ( parameterAsEnum( parameters, u
"TILE_FORMAT"_s, context ) )
499 mTileFormat = u
"PNG"_s;
502 mTileFormat = u
"JPG"_s;
505 mTileFormat = u
"WEBP"_s;
508 mTileFormat = u
"PNG"_s;
512 mJpgQuality = mTileFormat !=
"PNG"_L1 ? parameterAsInt( parameters, u
"QUALITY"_s, context ) : -1;
513 mMetaTileSize = parameterAsInt( parameters, u
"METATILESIZE"_s, context );
518 if ( ( mTileFormat !=
"PNG"_L1 && mTileFormat !=
"WEBP"_L1 ) && mBackgroundColor.alpha() != 255 )
521 QObject::tr(
"A semi-transparent background color was set, but the JPG format only supports fully opaque colors. The background color setting will be ignored. Please use a fully opaque background color instead." )
534 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
540 QObject::tr(
"Layer %1 will be skipped as the algorithm leads to bulk downloading behavior which is prohibited by the %2OpenStreetMap Foundation tile usage policy%3" )
541 .arg( layer->name(), u
"<a href=\"https://operations.osmfoundation.org/policies/tiles/\">"_s, u
"</a>"_s ),
542 QObject::tr(
"Layer %1 will be skipped as the algorithm leads to bulk downloading behavior which is prohibited by the %2OpenStreetMap Foundation tile usage policy%3" )
543 .arg( layer->name(), QString(), QString() )
545 mLayers.removeAll( layer );
552std::optional< QgsMapSettings > QgsXyzTilesBaseAlgorithm::mapSettingsForTile(
const MetaTile &metaTile )
const
569 if ( mTileFormat ==
"PNG"_L1 || mTileFormat ==
"WEBP"_L1 || mBackgroundColor.alpha() == 255 )
573 QSize size( mTileWidth * metaTile.rows, mTileHeight * metaTile.cols );
589 while ( mRendererJobs.size() < mThreadsNumber && !mMetaTiles.empty() )
594 MetaTile metaTile = mMetaTiles.takeFirst();
595 const std::optional<QgsMapSettings> settings = mapSettingsForTile( metaTile );
596 if ( !settings.has_value() )
598 mProcessedMetaTiles++;
599 feedback->
setProgress( 100.0 * mProcessedMetaTiles / mTotalMetaTiles );
604 mRendererJobs.insert( job, metaTile );
607 const MetaTile tile = mRendererJobs.take( job );
611 mProcessedMetaTiles++;
612 feedback->
setProgress( 100.0 * mProcessedMetaTiles / mTotalMetaTiles );
614 processMetaTile( tile, renderedImage, feedback );
618 startJobs( feedback );
620 checkPipelineFinished( feedback );
626 checkPipelineFinished( feedback );
631 if ( feedback->
isCanceled() || ( mMetaTiles.isEmpty() && mRendererJobs.isEmpty() && mActivePostProcessingTasks == 0 ) )
644QString QgsXyzTilesDirectoryAlgorithm::name()
const
646 return u
"tilesxyzdirectory"_s;
649QString QgsXyzTilesDirectoryAlgorithm::displayName()
const
651 return QObject::tr(
"Generate XYZ tiles (Directory)" );
654QStringList QgsXyzTilesDirectoryAlgorithm::tags()
const
656 return QObject::tr(
"tiles,xyz,tms,directory" ).split(
',' );
659QString QgsXyzTilesDirectoryAlgorithm::shortHelpString()
const
662 "This algorithm generates XYZ raster tiles from the current project and saves them as individual image files in a structured directory hierarchy ({z}/{x}/{y}.png or .jpg).\n\n"
663 "All visible map layers from the project will be rendered into tiles across the specified extent and zoom range.\n\n"
664 "Optionally, a standalone Leaflet HTML file can be generated for instant web previewing of the tiles."
668QString QgsXyzTilesDirectoryAlgorithm::shortDescription()
const
670 return QObject::tr(
"Generates XYZ tiles from the project as a structured directory hierarchy ({z}/{x}/{y}.png/jpg)." );
673QgsXyzTilesDirectoryAlgorithm *QgsXyzTilesDirectoryAlgorithm::createInstance()
const
675 return new QgsXyzTilesDirectoryAlgorithm();
678void QgsXyzTilesDirectoryAlgorithm::initAlgorithm(
const QVariantMap & )
680 createCommonParameters();
681 createTileMatrixParameters();
684 tileWidthParam->setHelp( QObject::tr(
"Width of each tile image in pixels." ) );
685 addParameter( tileWidthParam.release() );
688 tileHeightParam->setHelp( QObject::tr(
"Height of each tile image in pixels." ) );
689 addParameter( tileHeightParam.release() );
691 auto tmsParam = std::make_unique<QgsProcessingParameterBoolean>( u
"TMS_CONVENTION"_s, QObject::tr(
"Use inverted tile Y axis (TMS convention)" ),
false );
692 tmsParam->setHelp( QObject::tr(
"Inverts the Y tile coordinate naming convention to follow TMS format." ) );
693 addParameter( tmsParam.release() );
695 auto titleParam = std::make_unique<QgsProcessingParameterString>( u
"HTML_TITLE"_s, QObject::tr(
"Leaflet HTML output title" ), QVariant(),
false,
true );
697 titleParam->setHelp( QObject::tr(
"Title displayed in the generated Leaflet HTML web viewer." ) );
698 addParameter( titleParam.release() );
700 auto attributionParam = std::make_unique<QgsProcessingParameterString>( u
"HTML_ATTRIBUTION"_s, QObject::tr(
"Leaflet HTML output attribution" ), QVariant(),
false,
true );
702 attributionParam->setHelp( QObject::tr(
"Attribution text displayed in the generated Leaflet HTML web viewer." ) );
703 addParameter( attributionParam.release() );
705 auto osmParam = std::make_unique<QgsProcessingParameterBoolean>( u
"HTML_OSM"_s, QObject::tr(
"Include OpenStreetMap basemap in Leaflet HTML output" ),
false );
707 osmParam->setHelp( QObject::tr(
"Includes an OpenStreetMap background layer in the generated Leaflet HTML viewer." ) );
708 addParameter( osmParam.release() );
710 auto outputDirParam = std::make_unique<QgsProcessingParameterFolderDestination>( u
"OUTPUT_DIRECTORY"_s, QObject::tr(
"Output directory" ) );
711 outputDirParam->setHelp( QObject::tr(
"Destination folder where the generated directory structure and tile files will be stored." ) );
712 addParameter( outputDirParam.release() );
714 auto outputHtmlParam = std::make_unique<QgsProcessingParameterFileDestination>( u
"OUTPUT_HTML"_s, QObject::tr(
"Output HTML (Leaflet)" ), QObject::tr(
"HTML files (*.html)" ), QVariant(),
true );
715 outputHtmlParam->setHelp( QObject::tr(
"Destination file path for the optional Leaflet HTML web map preview." ) );
716 addParameter( outputHtmlParam.release() );
723 QGS_MARK_ALGORITHM_SOURCE
725 const bool tms = parameterAsBoolean( parameters, u
"TMS_CONVENTION"_s, context );
726 const QString title = parameterAsString( parameters, u
"HTML_TITLE"_s, context );
727 const QString attribution = parameterAsString( parameters, u
"HTML_ATTRIBUTION"_s, context );
728 const bool useOsm = parameterAsBoolean( parameters, u
"HTML_OSM"_s, context );
729 QString outputDir = parameterAsString( parameters, u
"OUTPUT_DIRECTORY"_s, context );
730 const QString outputHtml = parameterAsString( parameters, u
"OUTPUT_HTML"_s, context );
732 mOutputDir = outputDir;
735 long long totalTiles = 0;
737 for (
int z = mMinZoom; z <= mMaxZoomLimitIncludingOverrides; z++ )
742 long long tileCount = 0;
743 mMetaTiles += getMetatiles( mZ0matrix, mTileGenerationRegion, z, tileCount, mMetaTileSize, mMaxZoomRegions, mMaxZoom );
744 feedback->
pushInfo( QObject::tr(
"%1 metatiles (%2 tiles) will be created for zoom level %3" ).arg( mMetaTiles.size() - mTotalMetaTiles ).arg( tileCount ).arg( z ) );
745 mTotalMetaTiles = mMetaTiles.size();
746 totalTiles += tileCount;
748 if ( mTotalMetaTiles == 0 )
750 throw QgsProcessingException( QObject::tr(
"No metatiles will be created -- please check the extent and zoom limits" ) );
753 feedback->
pushInfo( QObject::tr(
"A total of %1 metatiles (%2 tiles) will be created" ).arg( mTotalMetaTiles ).arg( totalTiles ) );
755 checkLayersUsagePolicy( feedback );
757 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
759 layer->moveToThread( QThread::currentThread() );
762 doExport( feedback );
764 qDeleteAll( mLayers );
767 if ( mSkipEmptyTiles )
769 feedback->
pushInfo( QObject::tr(
"Wrote %1 total tiles, skipped %2 empty tiles" ).arg( mTilesWritten.load() ).arg( mEmptyTiles.load() ) );
773 results.insert( u
"OUTPUT_DIRECTORY"_s, outputDir );
775 if ( !outputHtml.isEmpty() )
777 const QString osm = QStringLiteral(
778 "var osm_layer = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png',"
779 "{minZoom: %1, maxZoom: %2, attribution: '© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors'}).addTo(map);"
782 .arg( mMaxZoomLimitIncludingOverrides );
784 const QString addOsm = useOsm ? osm : QString();
785 const QString tmsConvention = tms ? u
"true"_s : u
"false"_s;
786 const QString attr = attribution.isEmpty() ? u
"Created by QGIS"_s : attribution;
787 const QString tileSource = u
"'file:///%1/{z}/{x}/{y}.%2'"_s.arg( outputDir.replace(
"\\",
"/" ).toHtmlEscaped(), mTileFormat.toLower() );
789 const QString html = QStringLiteral(
790 "<!DOCTYPE html><html><head><title>%1</title><meta charset=\"utf-8\"/>"
791 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
792 "<link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.css\""
793 "integrity=\"sha384-sHL9NAb7lN7rfvG5lfHpm643Xkcjzp4jFvuavGOndn6pjVqS6ny56CAt3nsEVT4H\""
795 "<script src=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.js\""
796 "integrity=\"sha384-cxOPjt7s7Iz04uaHJceBmS+qpjv2JkIHNVcuOrM+YHwZOmJGBXI00mdUXEq65HTH\""
797 "crossorigin=\"\"></script>"
798 "<style type=\"text/css\">body {margin: 0;padding: 0;} html, body, #map{width: 100%;height: 100%;}</style></head>"
799 "<body><div id=\"map\"></div><script>"
800 "var map = L.map('map', {attributionControl: false}).setView([%2, %3], %4);"
801 "L.control.attribution({prefix: false}).addTo(map);"
803 "var tilesource_layer = L.tileLayer(%6, {minZoom: %7, maxZoom: %8, tms: %9, attribution: '%10'}).addTo(map);"
804 "</script></body></html>"
806 .arg( title.isEmpty() ? u
"Leaflet preview"_s : title )
807 .arg( mWgs84Extent.center().y() )
808 .arg( mWgs84Extent.center().x() )
809 .arg( ( mMaxZoom + mMinZoom ) / 2 )
810 .arg( addOsm, tileSource )
812 .arg( mMaxZoomLimitIncludingOverrides )
813 .arg( tmsConvention, attr );
815 QFile htmlFile( outputHtml );
816 if ( !htmlFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
820 QTextStream fout( &htmlFile );
823 results.insert( u
"OUTPUT_HTML"_s, outputHtml );
829 const QString layerUri
830 = u
"type=xyz&url=file:///%1/%7Bz%7D/%7Bx%7D/%7By%7D.%2&zmax=%3&zmin=%4"_s.arg( outputDir.replace(
"\\",
"/" ).toHtmlEscaped(), mTileFormat.toLower() ).arg( mMaxZoom ).arg( mMinZoom );
831 auto layer = std::make_unique<QgsRasterLayer>( layerUri,
"OUTPUT_LAYER", u
"wms"_s );
832 if ( !layer->isValid() )
834 feedback->
reportError( QObject::tr(
"Failed to open XYZ directory as a raster layer" ) );
836 const QString layerId = layer->id();
838 details.setOutputLayerName( layer.get() );
841 results.insert( u
"OUTPUT_LAYER"_s, layerId );
847void QgsXyzTilesDirectoryAlgorithm::processMetaTile(
const MetaTile &metaTile,
const QImage &renderedImage,
QgsProcessingFeedback *feedback )
849 mActivePostProcessingTasks++;
851 mPostProcessingPool->start( [
this, metaTile, renderedImage, feedback]() {
852 const bool testEmptyTilesUsingAlpha0 = mTileFormat !=
"JPG"_L1 && mBackgroundColor.alpha() == 0;
853 long long localWritten = 0;
854 long long localEmpty = 0;
856 QSet<QString> createdDirs;
858 for (
auto it = metaTile.tiles.constBegin(); it != metaTile.tiles.constEnd(); ++it )
863 const QPair<int, int> tm = it.key();
864 const QImage tileImage = renderedImage.copy( mTileWidth * tm.first, mTileHeight * tm.second, mTileWidth, mTileHeight );
872 const Tile tile = it.value();
873 const QString dirPath = u
"%1/%2/%3"_s.arg( mOutputDir ).arg( tile.z ).arg( tile.x );
874 if ( !createdDirs.contains( dirPath ) )
876 QDir().mkpath( dirPath );
877 createdDirs.insert( dirPath );
880 const int y = mTms ? tile2tms( tile.y, tile.z ) : tile.y;
881 const QString filePath = u
"%1/%2.%3"_s.arg( dirPath ).arg( y ).arg( mTileFormat.toLower() );
882 tileImage.save( filePath, mTileFormat.toStdString().c_str(), mJpgQuality );
887 mTilesWritten += localWritten;
888 mEmptyTiles += localEmpty;
890 mActivePostProcessingTasks--;
891 checkPipelineFinished( feedback );
897 mPostProcessingPool = std::make_unique<QThreadPool>();
898 mPostProcessingPool->setMaxThreadCount( std::max( 1, mThreadsNumber ) );
902 mJobOwner.reset(
new QObject() );
904 startJobs( feedback );
906 if ( !mMetaTiles.isEmpty() || !mRendererJobs.isEmpty() || mActivePostProcessingTasks.load() > 0 )
911 for (
auto it = mRendererJobs.constBegin(); it != mRendererJobs.constEnd(); it++ )
914 it.key()->deleteLater();
916 mRendererJobs.clear();
918 mPostProcessingPool->waitForDone();
919 mPostProcessingPool.reset();
920 mEventLoop =
nullptr;
928QString QgsXyzTilesMbtilesAlgorithm::name()
const
930 return u
"tilesxyzmbtiles"_s;
933QString QgsXyzTilesMbtilesAlgorithm::displayName()
const
935 return QObject::tr(
"Generate XYZ tiles (MBTiles)" );
938QStringList QgsXyzTilesMbtilesAlgorithm::tags()
const
940 return QObject::tr(
"tiles,xyz,tms,mbtiles" ).split(
',' );
943QString QgsXyzTilesMbtilesAlgorithm::shortHelpString()
const
946 "This algorithm generates XYZ raster tiles from the current project and packages them into a single, portable MBTiles (SQLite) database file.\n\n"
947 "All visible map layers from the project will be rendered into tiles across the specified extent and zoom range."
951QString QgsXyzTilesMbtilesAlgorithm::shortDescription()
const
953 return QObject::tr(
"Generates XYZ tiles from the project as a single, portable MBTiles (SQLite) database." );
956QgsXyzTilesMbtilesAlgorithm *QgsXyzTilesMbtilesAlgorithm::createInstance()
const
958 return new QgsXyzTilesMbtilesAlgorithm();
961void QgsXyzTilesMbtilesAlgorithm::initAlgorithm(
const QVariantMap & )
963 createCommonParameters();
971 QGS_MARK_ALGORITHM_SOURCE
973 const QString outputFile = parameterAsString( parameters, u
"OUTPUT_FILE"_s, context );
974 if ( QFile::exists( outputFile ) )
976 feedback->
pushWarning( QObject::tr(
"Removing existing file '%1'" ).arg( QDir::toNativeSeparators( outputFile ) ) );
977 if ( !QFile( outputFile ).remove() )
979 throw QgsProcessingException( QObject::tr(
"Could not remove existing file '%1'" ).arg( QDir::toNativeSeparators( outputFile ) ) );
983 mMbtilesWriter = std::make_unique<QgsMbTiles>( outputFile );
986 if ( !mMbtilesWriter->create(
true ) )
988 throw QgsProcessingException( QObject::tr(
"Failed to create MBTiles file %1: %2" ).arg( outputFile, mMbtilesWriter->lastError() ) );
990 mMbtilesWriter->setMetadataValue( u
"format"_s, mTileFormat.toLower() );
991 mMbtilesWriter->setMetadataValue( u
"name"_s, QFileInfo( outputFile ).baseName() );
992 mMbtilesWriter->setMetadataValue( u
"description"_s, QFileInfo( outputFile ).baseName() );
993 mMbtilesWriter->setMetadataValue( u
"version"_s, u
"1.1"_s );
994 mMbtilesWriter->setMetadataValue( u
"type"_s, u
"overlay"_s );
995 mMbtilesWriter->setMetadataValue( u
"minzoom"_s, QString::number( mMinZoom ) );
996 mMbtilesWriter->setMetadataValue( u
"maxzoom"_s, QString::number( mMaxZoomLimitIncludingOverrides ) );
997 QString boundsStr = QString( u
"%1,%2,%3,%4"_s ).arg( mWgs84Extent.xMinimum() ).arg( mWgs84Extent.yMinimum() ).arg( mWgs84Extent.xMaximum() ).arg( mWgs84Extent.yMaximum() );
998 mMbtilesWriter->setMetadataValue( u
"bounds"_s, boundsStr );
1000 long long totalTiles = 0;
1001 mTotalMetaTiles = 0;
1002 for (
int z = mMinZoom; z <= mMaxZoomLimitIncludingOverrides; z++ )
1007 long long tileCount = 0;
1008 mMetaTiles += getMetatiles( mZ0matrix, mTileGenerationRegion, z, tileCount, mMetaTileSize, mMaxZoomRegions, mMaxZoom );
1009 feedback->
pushInfo( QObject::tr(
"%1 metatiles (%2 tiles) will be created for zoom level %3" ).arg( mMetaTiles.size() - mTotalMetaTiles ).arg( tileCount ).arg( z ) );
1010 mTotalMetaTiles = mMetaTiles.size();
1011 totalTiles += tileCount;
1013 if ( mTotalMetaTiles == 0 )
1015 throw QgsProcessingException( QObject::tr(
"No metatiles will be created -- please check the extent and zoom limits" ) );
1018 feedback->
pushInfo( QObject::tr(
"A total of %1 metatiles (%2 tiles) will be created" ).arg( mTotalMetaTiles ).arg( totalTiles ) );
1020 checkLayersUsagePolicy( feedback );
1022 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
1024 layer->moveToThread( QThread::currentThread() );
1027 doExport( feedback );
1029 qDeleteAll( mLayers );
1034 mMbtilesWriter->finalize();
1037 if ( mSkipEmptyTiles )
1039 feedback->
pushInfo( QObject::tr(
"Wrote %1 total tiles, skipped %2 empty tiles" ).arg( mTilesWritten.load() ).arg( mEmptyTiles.load() ) );
1041 QVariantMap results;
1042 results.insert( u
"OUTPUT_FILE"_s, outputFile );
1047 auto layer = std::make_unique<QgsRasterLayer>( outputFile,
"OUTPUT_LAYER", u
"gdal"_s );
1048 if ( !layer->isValid() )
1050 feedback->
reportError( QObject::tr(
"Failed to open MBTiles file as a raster layer" ) );
1052 const QString layerId = layer->id();
1054 details.setOutputLayerName( layer.get() );
1057 results.insert( u
"OUTPUT_LAYER"_s, layerId );
1063void QgsXyzTilesMbtilesAlgorithm::processMetaTile(
const MetaTile &metaTile,
const QImage &renderedImg,
QgsProcessingFeedback *feedback )
1065 mActivePostProcessingTasks++;
1067 mPostProcessingPool->start( [
this, feedback, metaTile, renderedImg]() {
1068 const bool testEmptyTilesUsingAlpha0 = mTileFormat !=
"JPG"_L1 && mBackgroundColor.alpha() == 0;
1069 long long localWritten = 0;
1070 long long localEmpty = 0;
1072 QList<QgsMbTiles::TileData> metatileTiles;
1073 metatileTiles.reserve( metaTile.tiles.size() );
1075 for (
auto it = metaTile.tiles.constBegin(); it != metaTile.tiles.constEnd(); ++it )
1080 const QPair<int, int> tm = it.key();
1082 const QImage tileImage = renderedImg.copy( mTileWidth * tm.first, mTileHeight * tm.second, mTileWidth, mTileHeight );
1092 QBuffer buffer( &bytes );
1093 buffer.open( QIODevice::WriteOnly );
1094 tileImage.save( &buffer, mTileFormat.toStdString().c_str(), mJpgQuality );
1096 const Tile tile = it.value();
1097 const int tileY = tile2tms( tile.y, tile.z );
1098 metatileTiles.append( { tile.z, tile.x, tileY, bytes } );
1102 mWriteQueue->push( metatileTiles );
1104 mTilesWritten += localWritten;
1105 mEmptyTiles += localEmpty;
1107 mActivePostProcessingTasks--;
1108 checkPipelineFinished( feedback );
1114 mPostProcessingPool = std::make_unique<QThreadPool>();
1115 mPostProcessingPool->setMaxThreadCount( std::max( 1, mThreadsNumber ) );
1117 PendingTilesToWriteQueue< QgsMbTiles::TileData > queue;
1118 mWriteQueue = &queue;
1120 QThread *dbThread = QThread::create( [
this, &queue]() {
1121 QList<QgsMbTiles::TileData> batch;
1122 constexpr int BATCH_SIZE = 10000;
1123 batch.reserve( BATCH_SIZE );
1124 while ( queue.popBatch( batch, BATCH_SIZE ) )
1126 mMbtilesWriter->setTileData( batch );
1134 mJobOwner.reset(
new QObject() );
1136 startJobs( feedback );
1138 if ( !mMetaTiles.isEmpty() || !mRendererJobs.isEmpty() || mActivePostProcessingTasks.load() > 0 )
1143 for (
auto it = mRendererJobs.constBegin(); it != mRendererJobs.constEnd(); it++ )
1146 it.key()->deleteLater();
1148 mRendererJobs.clear();
1150 mPostProcessingPool->waitForDone();
1151 mPostProcessingPool.reset();
1153 queue.setFinished();
1157 mWriteQueue =
nullptr;
1158 mEventLoop =
nullptr;
1166QString QgsXyzTilesGpkgAlgorithm::name()
const
1168 return u
"tilesxyzgpkg"_s;
1171QString QgsXyzTilesGpkgAlgorithm::displayName()
const
1173 return QObject::tr(
"Generate XYZ tiles (GeoPackage)" );
1176QStringList QgsXyzTilesGpkgAlgorithm::tags()
const
1178 return QObject::tr(
"tiles,xyz,geopackage,gpkg,raster" ).split(
',' );
1181QString QgsXyzTilesGpkgAlgorithm::shortDescription()
const
1183 return QObject::tr(
"Renders maps to XYZ raster tiles into a GeoPackage raster tile database." );
1186QString QgsXyzTilesGpkgAlgorithm::shortHelpString()
const
1189 "This algorithm generates XYZ raster tiles from the current project and saves them into an OGC GeoPackage file.\n\n"
1190 "All visible map layers from the project will be rendered into tiles across the specified extent and zoom range."
1194QgsXyzTilesGpkgAlgorithm *QgsXyzTilesGpkgAlgorithm::createInstance()
const
1196 return new QgsXyzTilesGpkgAlgorithm();
1199void QgsXyzTilesGpkgAlgorithm::initAlgorithm(
const QVariantMap & )
1201 createCommonParameters();
1202 createTileMatrixParameters();
1205 tileWidthParam->setHelp( QObject::tr(
"Width of each tile image in pixels." ) );
1206 addParameter( tileWidthParam.release() );
1209 tileHeightParam->setHelp( QObject::tr(
"Height of each tile image in pixels." ) );
1210 addParameter( tileHeightParam.release() );
1219 QGS_MARK_ALGORITHM_SOURCE
1221 const QString outputFile = parameterAsString( parameters, u
"OUTPUT_FILE"_s, context );
1223 if ( QFile::exists( outputFile ) )
1225 feedback->
pushWarning( QObject::tr(
"Removing existing file '%1'" ).arg( QDir::toNativeSeparators( outputFile ) ) );
1226 if ( !QFile( outputFile ).remove() )
1228 throw QgsProcessingException( QObject::tr(
"Could not remove existing file '%1'" ).arg( QDir::toNativeSeparators( outputFile ) ) );
1232 mGpkgWriter = std::make_unique<QgsGeoPackageTiles>( outputFile );
1234 if ( !mGpkgWriter->create( mZ0matrix, mTileGenerationRegion, mMinZoom, mMaxZoomLimitIncludingOverrides, mTileWidth, mTileHeight ) )
1236 throw QgsProcessingException( QObject::tr(
"Failed to create GeoPackage file %1: %2" ).arg( outputFile, mGpkgWriter->lastError() ) );
1239 long long totalTiles = 0;
1240 mTotalMetaTiles = 0;
1241 for (
int z = mMinZoom; z <= mMaxZoomLimitIncludingOverrides; z++ )
1246 long long tileCount = 0;
1247 mMetaTiles += getMetatiles( mZ0matrix, mTileGenerationRegion, z, tileCount, mMetaTileSize, mMaxZoomRegions, mMaxZoom );
1248 feedback->
pushInfo( QObject::tr(
"%1 metatiles (%2 tiles) will be created for zoom level %3" ).arg( mMetaTiles.size() - mTotalMetaTiles ).arg( tileCount ).arg( z ) );
1249 mTotalMetaTiles = mMetaTiles.size();
1250 totalTiles += tileCount;
1252 if ( mTotalMetaTiles == 0 )
1254 throw QgsProcessingException( QObject::tr(
"No metatiles will be created -- please check the extent and zoom limits" ) );
1256 feedback->
pushInfo( QObject::tr(
"A total of %1 metatiles (%2 tiles) will be created" ).arg( mTotalMetaTiles ).arg( totalTiles ) );
1258 checkLayersUsagePolicy( feedback );
1260 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
1262 layer->moveToThread( QThread::currentThread() );
1264 mJobOwner.reset(
new QObject() );
1266 doExport( feedback );
1268 qDeleteAll( mLayers );
1273 mGpkgWriter->finalize();
1276 mGpkgWriter->close();
1278 if ( mSkipEmptyTiles )
1280 feedback->
pushInfo( QObject::tr(
"Wrote %1 total tiles, skipped %2 empty tiles" ).arg( mTilesWritten.load() ).arg( mEmptyTiles.load() ) );
1283 QVariantMap results;
1288 auto layer = std::make_unique<QgsRasterLayer>( outputFile,
"OUTPUT_LAYER", u
"gdal"_s );
1289 if ( !layer->isValid() )
1291 feedback->
reportError( QObject::tr(
"Failed to open GeoPackage file as a raster layer" ) );
1293 const QString layerId = layer->id();
1295 details.setOutputLayerName( layer.get() );
1298 results.insert( u
"OUTPUT_LAYER"_s, layerId );
1301 results.insert( u
"OUTPUT_FILE"_s, outputFile );
1305void QgsXyzTilesGpkgAlgorithm::processMetaTile(
const MetaTile &metaTile,
const QImage &renderedImg,
QgsProcessingFeedback *feedback )
1307 mActivePostProcessingTasks++;
1308 mPostProcessingPool->start( [
this, feedback, metaTile, renderedImg]() {
1309 const bool testEmptyTilesUsingAlpha0 = mTileFormat !=
"JPG"_L1 && mBackgroundColor.alpha() == 0;
1310 long long localWritten = 0;
1311 long long localEmpty = 0;
1313 QList<QgsGeoPackageTiles::TileData> metatileTiles;
1314 metatileTiles.reserve( metaTile.tiles.size() );
1316 for (
auto it = metaTile.tiles.constBegin(); it != metaTile.tiles.constEnd(); ++it )
1321 const QPair<int, int> tm = it.key();
1323 const QImage tileImage = renderedImg.copy( mTileWidth * tm.first, mTileHeight * tm.second, mTileWidth, mTileHeight );
1333 QBuffer buffer( &bytes );
1334 buffer.open( QIODevice::WriteOnly );
1335 tileImage.save( &buffer, mTileFormat.toStdString().c_str(), mJpgQuality );
1337 const Tile tile = it.value();
1339 metatileTiles.append( { tile.z, tile.x, tile.y, bytes } );
1343 mWriteQueue->push( metatileTiles );
1345 mTilesWritten += localWritten;
1346 mEmptyTiles += localEmpty;
1348 mActivePostProcessingTasks--;
1349 checkPipelineFinished( feedback );
1355 mPostProcessingPool = std::make_unique<QThreadPool>();
1356 mPostProcessingPool->setMaxThreadCount( std::max( 1, mThreadsNumber ) );
1358 PendingTilesToWriteQueue<QgsGeoPackageTiles::TileData> queue;
1359 mWriteQueue = &queue;
1361 QThread *dbThread = QThread::create( [
this, &queue]() {
1362 QList<QgsGeoPackageTiles::TileData> batch;
1363 constexpr int BATCH_SIZE = 10000;
1364 batch.reserve( BATCH_SIZE );
1365 while ( queue.popBatch( batch, BATCH_SIZE ) )
1367 mGpkgWriter->setTileData( batch );
1375 mJobOwner.reset(
new QObject() );
1377 startJobs( feedback );
1379 if ( !mMetaTiles.isEmpty() || !mRendererJobs.isEmpty() || mActivePostProcessingTasks.load() > 0 )
1384 for (
auto *j : mRendererJobs.keys() )
1389 mRendererJobs.clear();
1391 mPostProcessingPool->waitForDone();
1392 mPostProcessingPool.reset();
1394 queue.setFinished();
1398 mWriteQueue =
nullptr;
1399 mEventLoop =
nullptr;
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
@ UsePartialCandidates
Whether to use also label candidates that are partially outside of the map view.
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
@ Export
Renderer used for printing or exporting to a file.
@ RequiresProject
The algorithm requires that a valid QgsProject is available from the processing context in order to e...
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
@ Optional
Parameter is optional.
@ RenderMapTile
Draw map such that there are no problems between adjacent tiles.
@ UseRenderingOptimization
Enable vector simplification and other rendering optimizations.
@ Antialiasing
Enable anti-aliasing for map rendering.
@ HighQualityImageTransforms
Enable high quality image transformations, which results in better appearance of scaled or rotated ra...
Represents a coordinate reference system (CRS).
Custom exception class for Coordinate Reference System related exceptions.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Contains operations and filters which apply to QImages.
static bool isBlankImage(const QImage &image)
Tests whether an image is completely blank, i.e.
Stores global configuration for labeling engine.
void setFlag(Qgis::LabelingFlag f, bool enabled=true)
Sets whether a particual flag is enabled.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Layer tree node points to a map layer.
QList< QgsMapLayer * > layerOrder() const
The order in which layers will be rendered on the canvas.
QgsMapLayer * addMapLayer(QgsMapLayer *layer, bool takeOwnership=true)
Add a layer to the store.
static bool isOpenStreetMapLayer(QgsMapLayer *layer)
Returns true if the layer is served by OpenStreetMap server.
Base class for all map layer types.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void finished()
emitted when asynchronous rendering is finished (or canceled).
void start()
Start the rendering job and immediately return.
Job implementation that renders everything sequentially in one thread.
QImage renderedImage() override
Gets a preview/resulting image.
Contains configuration for rendering maps.
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns the global configuration of the labeling engine.
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of layers to render in the map.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
void setScaleMethod(Qgis::ScaleCalculationMethod method)
Sets the method to use for scale calculations for the map.
void setOutputDpi(double dpi)
Sets the dpi (dots per inch) used for conversion between real world units (e.g.
void setOutputImageFormat(QImage::Format format)
sets format of internal QImage
void setRendererUsage(Qgis::RendererUsage rendererUsage)
Sets the rendering usage.
void setRasterizedRenderingPolicy(Qgis::RasterizedRenderingPolicy policy)
Sets the policy controlling when rasterisation of content during renders is permitted.
void setExtent(const QgsRectangle &rect, bool magnified=true)
Sets the coordinates of the rectangle which should be rendered.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets the global configuration of the labeling engine.
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context, which stores various information regarding which datum transfo...
void setOutputSize(QSize size)
Sets the size of the resulting map image, in pixels.
void setBackgroundColor(const QColor &color)
Sets the background color of the map.
void setFlag(Qgis::MapSettingsFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected).
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination crs (coordinate reference system) for the map render.
virtual Qgis::ProcessingAlgorithmFlags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Details for layers to load into projects.
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
void addLayerToLoadOnCompletion(const QString &layer, const QgsProcessingContext::LayerDetails &details)
Adds a layer to load (by ID or datasource) into the canvas upon completion of the algorithm or model.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution.
int maximumThreads() const
Returns the (optional) number of threads to use when running algorithms.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
virtual void pushFormattedMessage(const QString &html, const QString &text)
Pushes a pre-formatted message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A raster layer output for processing algorithms.
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
static int maxZoomForTile(const QgsRectangle &tileExtent, const QList< QgsTileExtentMaxZoomRegion > ®ions, int defaultMaxZoom)
Evaluates the effective maximum zoom level for a given tileExtent.
@ Raster
Raster layer type.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
Qgis::ScaleCalculationMethod scaleMethod
A rectangle specified with double values.
A QgsRectangle with associated coordinate reference system.
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
QgsRectangle extent() const
Returns extent of the tile matrix.
int matrixWidth() const
Returns number of columns of the tile 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.
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.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define MAXIMUM_OPENSTREETMAP_TILES_FETCH
Represents a spatial region paired with a custom maximum zoom level.
QgsReferencedRectangle extent
Bounding box extent and associated CRS.