Merge pull request #9857 from marcel-dancak/tiles_xyz
New Processing Algorithm to generate raster XYZ tiles
@ -509,6 +509,13 @@ qgis:sumlinelengths: >
|
|||||||
qgis:texttofloat: >
|
qgis:texttofloat: >
|
||||||
This algorithm modifies the type of a given attribute in a vector layer, converting a text attribute containing numeric strings into a numeric attribute.
|
This algorithm modifies the type of a given attribute in a vector layer, converting a text attribute containing numeric strings into a numeric attribute.
|
||||||
|
|
||||||
|
qgis:tilesxyz: >
|
||||||
|
This algorithm generates raster XYZ tiles of map canvas content.
|
||||||
|
|
||||||
|
Tile images can be saved as individual images in directory structure, or as single file in MBTiles format.
|
||||||
|
|
||||||
|
Tile size is fixed to 256x256.
|
||||||
|
|
||||||
qgis:topologicalcoloring: >
|
qgis:topologicalcoloring: >
|
||||||
This algorithm assigns a color index to polygon features in such a way that no adjacent polygons share the same color index, whilst minimizing the number of colors required.
|
This algorithm assigns a color index to polygon features in such a way that no adjacent polygons share the same color index, whilst minimizing the number of colors required.
|
||||||
|
|
||||||
|
@ -134,6 +134,7 @@ from .SpatialJoinSummary import SpatialJoinSummary
|
|||||||
from .StatisticsByCategories import StatisticsByCategories
|
from .StatisticsByCategories import StatisticsByCategories
|
||||||
from .SumLines import SumLines
|
from .SumLines import SumLines
|
||||||
from .TextToFloat import TextToFloat
|
from .TextToFloat import TextToFloat
|
||||||
|
from .TilesXYZ import TilesXYZ
|
||||||
from .TinInterpolation import TinInterpolation
|
from .TinInterpolation import TinInterpolation
|
||||||
from .TopoColors import TopoColor
|
from .TopoColors import TopoColor
|
||||||
from .TruncateTable import TruncateTable
|
from .TruncateTable import TruncateTable
|
||||||
@ -244,6 +245,7 @@ class QgisAlgorithmProvider(QgsProcessingProvider):
|
|||||||
StatisticsByCategories(),
|
StatisticsByCategories(),
|
||||||
SumLines(),
|
SumLines(),
|
||||||
TextToFloat(),
|
TextToFloat(),
|
||||||
|
TilesXYZ(),
|
||||||
TinInterpolation(),
|
TinInterpolation(),
|
||||||
TopoColor(),
|
TopoColor(),
|
||||||
TruncateTable(),
|
TruncateTable(),
|
||||||
|
393
python/plugins/processing/algs/qgis/TilesXYZ.py
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
TilesXYZ.py
|
||||||
|
---------------------
|
||||||
|
Date : April 2019
|
||||||
|
Copyright : (C) 2019 by Lutra Consulting Limited
|
||||||
|
Email : marcel.dancak@lutraconsulting.co.uk
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'Marcel Dancak'
|
||||||
|
__date__ = 'April 2019'
|
||||||
|
__copyright__ = '(C) 2019 by Lutra Consulting Limited'
|
||||||
|
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
import os
|
||||||
|
import math
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
import ogr
|
||||||
|
import gdal
|
||||||
|
from qgis.PyQt.QtCore import QSize, Qt, QByteArray, QBuffer
|
||||||
|
from qgis.PyQt.QtGui import QColor, QImage, QPainter
|
||||||
|
from qgis.core import (QgsProcessingException,
|
||||||
|
QgsProcessingParameterEnum,
|
||||||
|
QgsProcessingParameterNumber,
|
||||||
|
QgsProcessingParameterBoolean,
|
||||||
|
QgsProcessingParameterString,
|
||||||
|
QgsProcessingParameterExtent,
|
||||||
|
QgsProcessingOutputFile,
|
||||||
|
QgsProcessingParameterFileDestination,
|
||||||
|
QgsProcessingParameterFolderDestination,
|
||||||
|
QgsGeometry,
|
||||||
|
QgsRectangle,
|
||||||
|
QgsMapSettings,
|
||||||
|
QgsCoordinateTransform,
|
||||||
|
QgsCoordinateReferenceSystem,
|
||||||
|
QgsMapRendererCustomPainterJob)
|
||||||
|
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||||
|
|
||||||
|
|
||||||
|
# Math functions taken from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames #spellok
|
||||||
|
def deg2num(lat_deg, lon_deg, zoom):
|
||||||
|
lat_rad = math.radians(lat_deg)
|
||||||
|
n = 2.0 ** zoom
|
||||||
|
xtile = int((lon_deg + 180.0) / 360.0 * n)
|
||||||
|
ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
|
||||||
|
return (xtile, ytile)
|
||||||
|
|
||||||
|
|
||||||
|
def num2deg(xtile, ytile, zoom):
|
||||||
|
n = 2.0 ** zoom
|
||||||
|
lon_deg = xtile / n * 360.0 - 180.0
|
||||||
|
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
|
||||||
|
lat_deg = math.degrees(lat_rad)
|
||||||
|
return (lat_deg, lon_deg)
|
||||||
|
|
||||||
|
|
||||||
|
class Tile:
|
||||||
|
def __init__(self, x, y, z):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.z = z
|
||||||
|
|
||||||
|
def extent(self):
|
||||||
|
lat1, lon1 = num2deg(self.x, self.y, self.z)
|
||||||
|
lat2, lon2 = num2deg(self.x + 1, self.y + 1, self.z)
|
||||||
|
return [lon1, lat2, lon2, lat1]
|
||||||
|
|
||||||
|
|
||||||
|
class MetaTile:
|
||||||
|
def __init__(self):
|
||||||
|
# list of tuple(row index, column index, Tile)
|
||||||
|
self.tiles = []
|
||||||
|
|
||||||
|
def add_tile(self, row, column, tile):
|
||||||
|
self.tiles.append((row, column, tile))
|
||||||
|
|
||||||
|
def rows(self):
|
||||||
|
return max([r for r, _, _ in self.tiles]) + 1
|
||||||
|
|
||||||
|
def columns(self):
|
||||||
|
return max([c for _, c, _ in self.tiles]) + 1
|
||||||
|
|
||||||
|
def extent(self):
|
||||||
|
_, _, first = self.tiles[0]
|
||||||
|
_, _, last = self.tiles[-1]
|
||||||
|
lat1, lon1 = num2deg(first.x, first.y, first.z)
|
||||||
|
lat2, lon2 = num2deg(last.x + 1, last.y + 1, first.z)
|
||||||
|
return [lon1, lat2, lon2, lat1]
|
||||||
|
|
||||||
|
|
||||||
|
def get_metatiles(extent, zoom, size=4):
|
||||||
|
west_edge, south_edge, east_edge, north_edge = extent
|
||||||
|
left_tile, top_tile = deg2num(north_edge, west_edge, zoom)
|
||||||
|
right_tile, bottom_tile = deg2num(south_edge, east_edge, zoom)
|
||||||
|
|
||||||
|
metatiles = {}
|
||||||
|
for i, x in enumerate(range(left_tile, right_tile + 1)):
|
||||||
|
for j, y in enumerate(range(top_tile, bottom_tile + 1)):
|
||||||
|
meta_key = '{}:{}'.format(int(i / size), int(j / size))
|
||||||
|
if meta_key not in metatiles:
|
||||||
|
metatiles[meta_key] = MetaTile()
|
||||||
|
metatile = metatiles[meta_key]
|
||||||
|
metatile.add_tile(i % size, j % size, Tile(x, y, zoom))
|
||||||
|
|
||||||
|
return list(metatiles.values())
|
||||||
|
|
||||||
|
|
||||||
|
class DirectoryWriter:
|
||||||
|
def __init__(self, folder, tile_params):
|
||||||
|
self.folder = folder
|
||||||
|
self.format = tile_params.get('format', 'PNG')
|
||||||
|
self.quality = tile_params.get('quality', -1)
|
||||||
|
|
||||||
|
def writeTile(self, tile, image):
|
||||||
|
directory = os.path.join(self.folder, str(tile.z), str(tile.x))
|
||||||
|
os.makedirs(directory, exist_ok=True)
|
||||||
|
path = os.path.join(directory, '{}.{}'.format(tile.y, self.format.lower()))
|
||||||
|
image.save(path, self.format, self.quality)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MBTilesWriter:
|
||||||
|
def __init__(self, filename, tile_params, extent, min_zoom, max_zoom):
|
||||||
|
base_dir = os.path.dirname(filename)
|
||||||
|
os.makedirs(base_dir, exist_ok=True)
|
||||||
|
self.filename = filename
|
||||||
|
self.extent = extent
|
||||||
|
self.tile_width = tile_params.get('width', 256)
|
||||||
|
self.tile_height = tile_params.get('height', 256)
|
||||||
|
tile_format = tile_params['format']
|
||||||
|
if tile_format == 'JPG':
|
||||||
|
tile_format = 'JPEG'
|
||||||
|
options = ['QUALITY=%s' % tile_params.get('quality', 75)]
|
||||||
|
else:
|
||||||
|
options = ['ZLEVEL=8']
|
||||||
|
driver = gdal.GetDriverByName('MBTiles')
|
||||||
|
ds = driver.Create(filename, 1, 1, 1, options=['TILE_FORMAT=%s' % tile_format] + options)
|
||||||
|
ds = None
|
||||||
|
sqlite_driver = ogr.GetDriverByName('SQLite')
|
||||||
|
ds = sqlite_driver.Open(filename, 1)
|
||||||
|
ds.ExecuteSQL("INSERT INTO metadata(name, value) VALUES ('{}', '{}');".format('minzoom', min_zoom))
|
||||||
|
ds.ExecuteSQL("INSERT INTO metadata(name, value) VALUES ('{}', '{}');".format('maxzoom', max_zoom))
|
||||||
|
# will be set properly after writing all tiles
|
||||||
|
ds.ExecuteSQL("INSERT INTO metadata(name, value) VALUES ('{}', '');".format('bounds'))
|
||||||
|
ds = None
|
||||||
|
self._zoom = None
|
||||||
|
|
||||||
|
def _initZoomLayer(self, zoom):
|
||||||
|
west_edge, south_edge, east_edge, north_edge = self.extent
|
||||||
|
first_tile = Tile(*deg2num(north_edge, west_edge, zoom), zoom)
|
||||||
|
last_tile = Tile(*deg2num(south_edge, east_edge, zoom), zoom)
|
||||||
|
|
||||||
|
first_tile_extent = first_tile.extent()
|
||||||
|
last_tile_extent = last_tile.extent()
|
||||||
|
zoom_extent = [
|
||||||
|
first_tile_extent[0],
|
||||||
|
last_tile_extent[1],
|
||||||
|
last_tile_extent[2],
|
||||||
|
first_tile_extent[3]
|
||||||
|
]
|
||||||
|
|
||||||
|
sqlite_driver = ogr.GetDriverByName('SQLite')
|
||||||
|
ds = sqlite_driver.Open(self.filename, 1)
|
||||||
|
bounds = ','.join(map(str, zoom_extent))
|
||||||
|
ds.ExecuteSQL("UPDATE metadata SET value='{}' WHERE name='bounds'".format(bounds))
|
||||||
|
ds = None
|
||||||
|
|
||||||
|
self._zoomDs = gdal.OpenEx(self.filename, 1, open_options=['ZOOM_LEVEL=%s' % first_tile.z])
|
||||||
|
self._first_tile = first_tile
|
||||||
|
self._zoom = zoom
|
||||||
|
|
||||||
|
def writeTile(self, tile, image):
|
||||||
|
if tile.z != self._zoom:
|
||||||
|
self._initZoomLayer(tile.z)
|
||||||
|
|
||||||
|
data = QByteArray()
|
||||||
|
buff = QBuffer(data)
|
||||||
|
image.save(buff, 'PNG')
|
||||||
|
|
||||||
|
mmap_name = '/vsimem/' + uuid4().hex
|
||||||
|
gdal.FileFromMemBuffer(mmap_name, data.data())
|
||||||
|
gdal_dataset = gdal.Open(mmap_name)
|
||||||
|
data = gdal_dataset.ReadRaster(0, 0, self.tile_width, self.tile_height)
|
||||||
|
gdal_dataset = None
|
||||||
|
gdal.Unlink(mmap_name)
|
||||||
|
|
||||||
|
xoff = (tile.x - self._first_tile.x) * self.tile_width
|
||||||
|
yoff = (tile.y - self._first_tile.y) * self.tile_height
|
||||||
|
self._zoomDs.WriteRaster(xoff, yoff, self.tile_width, self.tile_height, data)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self._zoomDs = None
|
||||||
|
sqlite_driver = ogr.GetDriverByName('SQLite')
|
||||||
|
ds = sqlite_driver.Open(self.filename, 1)
|
||||||
|
bounds = ','.join(map(str, self.extent))
|
||||||
|
ds.ExecuteSQL("UPDATE metadata SET value='{}' WHERE name='bounds'".format(bounds))
|
||||||
|
ds = None
|
||||||
|
|
||||||
|
|
||||||
|
class TilesXYZ(QgisAlgorithm):
|
||||||
|
EXTENT = 'EXTENT'
|
||||||
|
ZOOM_MIN = 'ZOOM_MIN'
|
||||||
|
ZOOM_MAX = 'ZOOM_MAX'
|
||||||
|
TILE_FORMAT = 'TILE_FORMAT'
|
||||||
|
DPI = 'DPI'
|
||||||
|
OUTPUT_FORMAT = 'OUTPUT_FORMAT'
|
||||||
|
OUTPUT_DIRECTORY = 'OUTPUT_DIRECTORY'
|
||||||
|
OUTPUT_FILE = 'OUTPUT_FILE'
|
||||||
|
|
||||||
|
def group(self):
|
||||||
|
return self.tr('Raster tools')
|
||||||
|
|
||||||
|
def groupId(self):
|
||||||
|
return 'rastertools'
|
||||||
|
|
||||||
|
def initAlgorithm(self, config=None):
|
||||||
|
self.addParameter(QgsProcessingParameterExtent(self.EXTENT, self.tr('Extent')))
|
||||||
|
self.addParameter(QgsProcessingParameterNumber(self.ZOOM_MIN,
|
||||||
|
self.tr('Minimum zoom'),
|
||||||
|
minValue=0,
|
||||||
|
maxValue=25,
|
||||||
|
defaultValue=12))
|
||||||
|
self.addParameter(QgsProcessingParameterNumber(self.ZOOM_MAX,
|
||||||
|
self.tr('Maximum zoom'),
|
||||||
|
minValue=0,
|
||||||
|
maxValue=25,
|
||||||
|
defaultValue=12))
|
||||||
|
self.addParameter(QgsProcessingParameterNumber(self.DPI,
|
||||||
|
self.tr('DPI'),
|
||||||
|
minValue=48,
|
||||||
|
maxValue=600,
|
||||||
|
defaultValue=96))
|
||||||
|
self.formats = ['PNG', 'JPG']
|
||||||
|
self.addParameter(QgsProcessingParameterEnum(self.TILE_FORMAT,
|
||||||
|
self.tr('Tile format'),
|
||||||
|
self.formats,
|
||||||
|
defaultValue=0))
|
||||||
|
self.outputs = ['Directory', 'MBTiles']
|
||||||
|
self.addParameter(QgsProcessingParameterEnum(self.OUTPUT_FORMAT,
|
||||||
|
self.tr('Output format'),
|
||||||
|
self.outputs,
|
||||||
|
defaultValue=0))
|
||||||
|
self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT_DIRECTORY,
|
||||||
|
self.tr('Output directory'),
|
||||||
|
optional=True))
|
||||||
|
self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_FILE,
|
||||||
|
self.tr('Output file (for MBTiles)'),
|
||||||
|
self.tr('MBTiles files (*.mbtiles)'),
|
||||||
|
optional=True))
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
return 'tilesxyz'
|
||||||
|
|
||||||
|
def displayName(self):
|
||||||
|
return self.tr('Generate XYZ tiles')
|
||||||
|
|
||||||
|
def prepareAlgorithm(self, parameters, context, feedback):
|
||||||
|
project = context.project()
|
||||||
|
visible_layers = [item.layer() for item in project.layerTreeRoot().findLayers() if item.isVisible()]
|
||||||
|
self.layers = [l for l in project.layerTreeRoot().layerOrder() if l in visible_layers]
|
||||||
|
return True
|
||||||
|
|
||||||
|
def processAlgorithm(self, parameters, context, feedback):
|
||||||
|
feedback.setProgress(1)
|
||||||
|
|
||||||
|
extent = self.parameterAsExtent(parameters, self.EXTENT, context)
|
||||||
|
min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context)
|
||||||
|
max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context)
|
||||||
|
dpi = self.parameterAsInt(parameters, self.DPI, context)
|
||||||
|
tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)]
|
||||||
|
output_format = self.outputs[self.parameterAsEnum(parameters, self.OUTPUT_FORMAT, context)]
|
||||||
|
if output_format == 'Directory':
|
||||||
|
output_dir = self.parameterAsString(parameters, self.OUTPUT_DIRECTORY, context)
|
||||||
|
if not output_dir:
|
||||||
|
raise QgsProcessingException(self.tr('You need to specify output directory.'))
|
||||||
|
else: # MBTiles
|
||||||
|
output_file = self.parameterAsString(parameters, self.OUTPUT_FILE, context)
|
||||||
|
if not output_file:
|
||||||
|
raise QgsProcessingException(self.tr('You need to specify output filename.'))
|
||||||
|
tile_width = 256
|
||||||
|
tile_height = 256
|
||||||
|
|
||||||
|
wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326')
|
||||||
|
dest_crs = QgsCoordinateReferenceSystem('EPSG:3857')
|
||||||
|
|
||||||
|
project = context.project()
|
||||||
|
src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext())
|
||||||
|
wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext())
|
||||||
|
|
||||||
|
settings = QgsMapSettings()
|
||||||
|
settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied)
|
||||||
|
settings.setDestinationCrs(dest_crs)
|
||||||
|
settings.setLayers(self.layers)
|
||||||
|
settings.setOutputDpi(dpi)
|
||||||
|
|
||||||
|
wgs_extent = src_to_wgs.transformBoundingBox(extent)
|
||||||
|
wgs_extent = [wgs_extent.xMinimum(), wgs_extent.yMinimum(), wgs_extent.xMaximum(), wgs_extent.yMaximum()]
|
||||||
|
|
||||||
|
metatiles_by_zoom = {}
|
||||||
|
metatiles_count = 0
|
||||||
|
for zoom in range(min_zoom, max_zoom + 1):
|
||||||
|
metatiles = get_metatiles(wgs_extent, zoom, 4)
|
||||||
|
metatiles_by_zoom[zoom] = metatiles
|
||||||
|
metatiles_count += len(metatiles)
|
||||||
|
|
||||||
|
lab_buffer_px = 100
|
||||||
|
progress = 0
|
||||||
|
|
||||||
|
tile_params = {
|
||||||
|
'format': tile_format,
|
||||||
|
'quality': 75,
|
||||||
|
'width': tile_width,
|
||||||
|
'height': tile_height
|
||||||
|
}
|
||||||
|
if output_format == 'Directory':
|
||||||
|
writer = DirectoryWriter(output_dir, tile_params)
|
||||||
|
else:
|
||||||
|
writer = MBTilesWriter(output_file, tile_params, wgs_extent, min_zoom, max_zoom)
|
||||||
|
|
||||||
|
for zoom in range(min_zoom, max_zoom + 1):
|
||||||
|
feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom)
|
||||||
|
|
||||||
|
for i, metatile in enumerate(metatiles_by_zoom[zoom]):
|
||||||
|
size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns())
|
||||||
|
extent = QgsRectangle(*metatile.extent())
|
||||||
|
settings.setExtent(wgs_to_dest.transformBoundingBox(extent))
|
||||||
|
settings.setOutputSize(size)
|
||||||
|
|
||||||
|
label_area = QgsRectangle(settings.extent())
|
||||||
|
lab_buffer = label_area.width() * (lab_buffer_px / size.width())
|
||||||
|
label_area.set(
|
||||||
|
label_area.xMinimum() + lab_buffer,
|
||||||
|
label_area.yMinimum() + lab_buffer,
|
||||||
|
label_area.xMaximum() - lab_buffer,
|
||||||
|
label_area.yMaximum() - lab_buffer
|
||||||
|
)
|
||||||
|
settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area))
|
||||||
|
|
||||||
|
image = QImage(size, QImage.Format_ARGB32_Premultiplied)
|
||||||
|
image.fill(Qt.transparent)
|
||||||
|
dpm = settings.outputDpi() / 25.4 * 1000
|
||||||
|
image.setDotsPerMeterX(dpm)
|
||||||
|
image.setDotsPerMeterY(dpm)
|
||||||
|
painter = QPainter(image)
|
||||||
|
job = QgsMapRendererCustomPainterJob(settings, painter)
|
||||||
|
job.renderSynchronously()
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
# For analysing metatiles (labels, etc.)
|
||||||
|
# metatile_dir = os.path.join(output_dir, str(zoom))
|
||||||
|
# os.makedirs(metatile_dir, exist_ok=True)
|
||||||
|
# image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i))
|
||||||
|
|
||||||
|
for r, c, tile in metatile.tiles:
|
||||||
|
tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height)
|
||||||
|
writer.writeTile(tile, tile_img)
|
||||||
|
|
||||||
|
progress += 1
|
||||||
|
feedback.setProgress(100 * (progress / metatiles_count))
|
||||||
|
|
||||||
|
writer.close()
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
if output_format == 'Directory':
|
||||||
|
results['OUTPUT_DIRECTORY'] = output_dir
|
||||||
|
else: # MBTiles
|
||||||
|
results['OUTPUT_FILE'] = output_file
|
||||||
|
return results
|
||||||
|
|
||||||
|
def checkParameterValues(self, parameters, context):
|
||||||
|
min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context)
|
||||||
|
max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context)
|
||||||
|
if max_zoom < min_zoom:
|
||||||
|
return False, self.tr('Invalid zoom levels range.')
|
||||||
|
|
||||||
|
return super().checkParameterValues(parameters, context)
|
@ -86,7 +86,12 @@ class AlgorithmsTest(object):
|
|||||||
:param defs: A python dict containing a test algorithm definition
|
:param defs: A python dict containing a test algorithm definition
|
||||||
"""
|
"""
|
||||||
self.vector_layer_params = {}
|
self.vector_layer_params = {}
|
||||||
QgsProject.instance().removeAllMapLayers()
|
QgsProject.instance().clear()
|
||||||
|
|
||||||
|
if 'project' in defs:
|
||||||
|
full_project_path = os.path.join(processingTestDataPath(), defs['project'])
|
||||||
|
project_read_success = QgsProject.instance().read(full_project_path)
|
||||||
|
self.assertTrue(project_read_success, 'Failed to load project file: ' + defs['project'])
|
||||||
|
|
||||||
if 'project_crs' in defs:
|
if 'project_crs' in defs:
|
||||||
QgsProject.instance().setCrs(QgsCoordinateReferenceSystem(defs['project_crs']))
|
QgsProject.instance().setCrs(QgsCoordinateReferenceSystem(defs['project_crs']))
|
||||||
@ -212,6 +217,9 @@ class AlgorithmsTest(object):
|
|||||||
basename = 'raster.tif'
|
basename = 'raster.tif'
|
||||||
filepath = os.path.join(outdir, basename)
|
filepath = os.path.join(outdir, basename)
|
||||||
return filepath
|
return filepath
|
||||||
|
elif param['type'] == 'directory':
|
||||||
|
outdir = tempfile.mkdtemp()
|
||||||
|
return outdir
|
||||||
|
|
||||||
raise KeyError("Unknown type '{}' specified for parameter".format(param['type']))
|
raise KeyError("Unknown type '{}' specified for parameter".format(param['type']))
|
||||||
|
|
||||||
@ -350,6 +358,11 @@ class AlgorithmsTest(object):
|
|||||||
result_filepath = results[id]
|
result_filepath = results[id]
|
||||||
|
|
||||||
self.assertFilesEqual(expected_filepath, result_filepath)
|
self.assertFilesEqual(expected_filepath, result_filepath)
|
||||||
|
elif 'directory' == expected_result['type']:
|
||||||
|
expected_dirpath = self.filepath_from_param(expected_result)
|
||||||
|
result_dirpath = results[id]
|
||||||
|
|
||||||
|
self.assertDirectoriesEqual(expected_dirpath, result_dirpath)
|
||||||
elif 'regex' == expected_result['type']:
|
elif 'regex' == expected_result['type']:
|
||||||
with open(results[id], 'r') as file:
|
with open(results[id], 'r') as file:
|
||||||
data = file.read()
|
data = file.read()
|
||||||
|
@ -194,6 +194,25 @@ OUTPUT:
|
|||||||
- 'Feature Count: 6'
|
- 'Feature Count: 6'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Directories
|
||||||
|
|
||||||
|
You can compare the content of an output directory by en expected result reference directory
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
OUTPUT_DIR:
|
||||||
|
name: expected/tiles_xyz/test_1
|
||||||
|
type: directory
|
||||||
|
```
|
||||||
|
|
||||||
|
### Algorithm Context
|
||||||
|
|
||||||
|
There are few more definitions that can modify context of the algorithm - these can be specified at top level of test:
|
||||||
|
|
||||||
|
- `project` - will load a specified QGIS project file before running the algorithm. If not specified, algorithm will run with empty project
|
||||||
|
- `project_crs` - overrides the default project CRS - e.g. `EPSG:27700`
|
||||||
|
- `ellipsoid` - overrides the default project ellipsoid used for measurements - e.g. `GRS80`
|
||||||
|
|
||||||
|
|
||||||
Running tests locally
|
Running tests locally
|
||||||
------------------
|
------------------
|
||||||
```bash
|
```bash
|
||||||
|
BIN
python/plugins/processing/tests/testdata/expected/xyztiles/1/0/0.png
vendored
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
python/plugins/processing/tests/testdata/expected/xyztiles/2/0/1.png
vendored
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
python/plugins/processing/tests/testdata/expected/xyztiles/2/1/1.png
vendored
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
python/plugins/processing/tests/testdata/expected/xyztiles/3/1/2.png
vendored
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
python/plugins/processing/tests/testdata/expected/xyztiles/3/1/3.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
python/plugins/processing/tests/testdata/expected/xyztiles/3/2/2.png
vendored
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
python/plugins/processing/tests/testdata/expected/xyztiles/3/2/3.png
vendored
Normal file
After Width: | Height: | Size: 5.5 KiB |
@ -7524,5 +7524,21 @@ tests:
|
|||||||
name: expected/join_to_nearest_no_matches.gml
|
name: expected/join_to_nearest_no_matches.gml
|
||||||
type: vector
|
type: vector
|
||||||
|
|
||||||
|
- name: Generate XYZ tiles
|
||||||
|
algorithm: qgis:tilesxyz
|
||||||
|
project: ../../../../../tests/testdata/xyztiles.qgs
|
||||||
|
project_crs: EPSG:3857
|
||||||
|
params:
|
||||||
|
EXTENT: -12535000,-9883000,3360000,5349000 [EPSG:3857]
|
||||||
|
ZOOM_MIN: 1
|
||||||
|
ZOOM_MAX: 3
|
||||||
|
TILE_FORMAT: 0 # png
|
||||||
|
OUTPUT_FORMAT: 0 # directory
|
||||||
|
|
||||||
|
results:
|
||||||
|
OUTPUT_DIRECTORY:
|
||||||
|
type: directory
|
||||||
|
name: expected/xyztiles
|
||||||
|
|
||||||
|
|
||||||
# See ../README.md for a description of the file format
|
# See ../README.md for a description of the file format
|
||||||
|
@ -29,6 +29,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import difflib
|
import difflib
|
||||||
import functools
|
import functools
|
||||||
|
import filecmp
|
||||||
|
|
||||||
from qgis.PyQt.QtCore import QVariant
|
from qgis.PyQt.QtCore import QVariant
|
||||||
from qgis.core import QgsApplication, QgsFeatureRequest, NULL
|
from qgis.core import QgsApplication, QgsFeatureRequest, NULL
|
||||||
@ -196,6 +197,20 @@ class TestCase(_TestCase):
|
|||||||
diff = list(diff)
|
diff = list(diff)
|
||||||
self.assertEqual(0, len(diff), ''.join(diff))
|
self.assertEqual(0, len(diff), ''.join(diff))
|
||||||
|
|
||||||
|
def assertDirectoriesEqual(self, dirpath_expected, dirpath_result):
|
||||||
|
""" Checks whether both directories have the same content (recursively) and raises an assertion error if not. """
|
||||||
|
dc = filecmp.dircmp(dirpath_expected, dirpath_result)
|
||||||
|
dc.report_full_closure()
|
||||||
|
|
||||||
|
def _check_dirs_equal_recursive(dcmp):
|
||||||
|
self.assertEqual(dcmp.left_only, [])
|
||||||
|
self.assertEqual(dcmp.right_only, [])
|
||||||
|
self.assertEqual(dcmp.diff_files, [])
|
||||||
|
for sub_dcmp in dcmp.subdirs.values():
|
||||||
|
_check_dirs_equal_recursive(sub_dcmp)
|
||||||
|
|
||||||
|
_check_dirs_equal_recursive(dc)
|
||||||
|
|
||||||
def assertGeometriesEqual(self, geom0, geom1, geom0_id='geometry 1', geom1_id='geometry 2', precision=14, topo_equal_check=False):
|
def assertGeometriesEqual(self, geom0, geom1, geom0_id='geometry 1', geom1_id='geometry 2', precision=14, topo_equal_check=False):
|
||||||
self.checkGeometriesEqual(geom0, geom1, geom0_id, geom1_id, use_asserts=True, precision=precision, topo_equal_check=topo_equal_check)
|
self.checkGeometriesEqual(geom0, geom1, geom0_id, geom1_id, use_asserts=True, precision=precision, topo_equal_check=topo_equal_check)
|
||||||
|
|
||||||
|
744
tests/testdata/xyztiles.qgs
vendored
Normal file
@ -0,0 +1,744 @@
|
|||||||
|
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||||
|
<qgis version="3.7.0-Master" projectname="">
|
||||||
|
<homePath path=""/>
|
||||||
|
<title></title>
|
||||||
|
<autotransaction active="0"/>
|
||||||
|
<evaluateDefaultValues active="0"/>
|
||||||
|
<trust active="0"/>
|
||||||
|
<projectCrs>
|
||||||
|
<spatialrefsys>
|
||||||
|
<proj4>+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs</proj4>
|
||||||
|
<srsid>3857</srsid>
|
||||||
|
<srid>3857</srid>
|
||||||
|
<authid>EPSG:3857</authid>
|
||||||
|
<description>WGS 84 / Pseudo-Mercator</description>
|
||||||
|
<projectionacronym>merc</projectionacronym>
|
||||||
|
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||||
|
<geographicflag>false</geographicflag>
|
||||||
|
</spatialrefsys>
|
||||||
|
</projectCrs>
|
||||||
|
<layer-tree-group>
|
||||||
|
<customproperties/>
|
||||||
|
<layer-tree-layer name="Land" checked="Qt::Checked" expanded="1" source="./polys.shp" providerKey="ogr" id="polys20151123133114244">
|
||||||
|
<customproperties/>
|
||||||
|
</layer-tree-layer>
|
||||||
|
<layer-tree-layer name="Roads" checked="Qt::Checked" expanded="1" source="./lines.shp" providerKey="ogr" id="lines20151123133101198">
|
||||||
|
<customproperties/>
|
||||||
|
</layer-tree-layer>
|
||||||
|
<custom-order enabled="0">
|
||||||
|
<item>polys20151123133114244</item>
|
||||||
|
<item>lines20151123133101198</item>
|
||||||
|
</custom-order>
|
||||||
|
</layer-tree-group>
|
||||||
|
<snapping-settings mode="1" type="2" unit="1" intersection-snapping="0" enabled="1" tolerance="20">
|
||||||
|
<individual-layer-settings>
|
||||||
|
<layer-setting type="2" units="1" enabled="1" tolerance="20" id="polys20151123133114244"/>
|
||||||
|
<layer-setting type="2" units="1" enabled="1" tolerance="20" id="lines20151123133101198"/>
|
||||||
|
</individual-layer-settings>
|
||||||
|
</snapping-settings>
|
||||||
|
<relations/>
|
||||||
|
<mapcanvas name="theMapCanvas" annotationsVisible="1">
|
||||||
|
<units>meters</units>
|
||||||
|
<extent>
|
||||||
|
<xmin>-12244360.81901275180280209</xmin>
|
||||||
|
<ymin>3360185.32420947728678584</ymin>
|
||||||
|
<xmax>-10173775.61578787304461002</xmax>
|
||||||
|
<ymax>5348862.70644816849380732</ymax>
|
||||||
|
</extent>
|
||||||
|
<rotation>0</rotation>
|
||||||
|
<destinationsrs>
|
||||||
|
<spatialrefsys>
|
||||||
|
<proj4>+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs</proj4>
|
||||||
|
<srsid>3857</srsid>
|
||||||
|
<srid>3857</srid>
|
||||||
|
<authid>EPSG:3857</authid>
|
||||||
|
<description>WGS 84 / Pseudo-Mercator</description>
|
||||||
|
<projectionacronym>merc</projectionacronym>
|
||||||
|
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||||
|
<geographicflag>false</geographicflag>
|
||||||
|
</spatialrefsys>
|
||||||
|
</destinationsrs>
|
||||||
|
<rendermaptile>0</rendermaptile>
|
||||||
|
<expressionContextScope/>
|
||||||
|
</mapcanvas>
|
||||||
|
<projectModels/>
|
||||||
|
<legend updateDrawingOrder="true">
|
||||||
|
<legendlayer checked="Qt::Checked" name="Land" showFeatureCount="0" drawingOrder="-1" open="true">
|
||||||
|
<filegroup hidden="false" open="true">
|
||||||
|
<legendlayerfile layerid="polys20151123133114244" visible="1" isInOverview="0"/>
|
||||||
|
</filegroup>
|
||||||
|
</legendlayer>
|
||||||
|
<legendlayer checked="Qt::Checked" name="Roads" showFeatureCount="0" drawingOrder="-1" open="true">
|
||||||
|
<filegroup hidden="false" open="true">
|
||||||
|
<legendlayerfile layerid="lines20151123133101198" visible="1" isInOverview="0"/>
|
||||||
|
</filegroup>
|
||||||
|
</legendlayer>
|
||||||
|
</legend>
|
||||||
|
<mapViewDocks/>
|
||||||
|
<mapViewDocks3D/>
|
||||||
|
<projectlayers>
|
||||||
|
<maplayer styleCategories="AllStyleCategories" minScale="1e+8" hasScaleBasedVisibilityFlag="0" simplifyAlgorithm="0" simplifyLocal="1" readOnly="0" type="vector" autoRefreshTime="0" autoRefreshEnabled="0" simplifyMaxScale="1" simplifyDrawingTol="1" refreshOnNotifyEnabled="0" geometry="Line" simplifyDrawingHints="1" labelsEnabled="1" refreshOnNotifyMessage="" maxScale="1">
|
||||||
|
<extent>
|
||||||
|
<xmin>-117.62319839219053108</xmin>
|
||||||
|
<ymin>23.20820580488508966</ymin>
|
||||||
|
<xmax>-82.32264950769274492</xmax>
|
||||||
|
<ymax>46.18290982947509349</ymax>
|
||||||
|
</extent>
|
||||||
|
<id>lines20151123133101198</id>
|
||||||
|
<datasource>./lines.shp</datasource>
|
||||||
|
<keywordList>
|
||||||
|
<value></value>
|
||||||
|
</keywordList>
|
||||||
|
<layername>Roads</layername>
|
||||||
|
<srs>
|
||||||
|
<spatialrefsys>
|
||||||
|
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||||
|
<srsid>3452</srsid>
|
||||||
|
<srid>4326</srid>
|
||||||
|
<authid>EPSG:4326</authid>
|
||||||
|
<description>WGS 84</description>
|
||||||
|
<projectionacronym>longlat</projectionacronym>
|
||||||
|
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||||
|
<geographicflag>true</geographicflag>
|
||||||
|
</spatialrefsys>
|
||||||
|
</srs>
|
||||||
|
<resourceMetadata>
|
||||||
|
<identifier></identifier>
|
||||||
|
<parentidentifier></parentidentifier>
|
||||||
|
<language></language>
|
||||||
|
<type></type>
|
||||||
|
<title></title>
|
||||||
|
<abstract></abstract>
|
||||||
|
<links/>
|
||||||
|
<fees></fees>
|
||||||
|
<encoding></encoding>
|
||||||
|
<crs>
|
||||||
|
<spatialrefsys>
|
||||||
|
<proj4></proj4>
|
||||||
|
<srsid>0</srsid>
|
||||||
|
<srid>0</srid>
|
||||||
|
<authid></authid>
|
||||||
|
<description></description>
|
||||||
|
<projectionacronym></projectionacronym>
|
||||||
|
<ellipsoidacronym></ellipsoidacronym>
|
||||||
|
<geographicflag>false</geographicflag>
|
||||||
|
</spatialrefsys>
|
||||||
|
</crs>
|
||||||
|
<extent/>
|
||||||
|
</resourceMetadata>
|
||||||
|
<provider encoding="UTF-8">ogr</provider>
|
||||||
|
<vectorjoins/>
|
||||||
|
<layerDependencies/>
|
||||||
|
<dataDependencies/>
|
||||||
|
<legend type="default-vector"/>
|
||||||
|
<expressionfields/>
|
||||||
|
<map-layer-style-manager current="default">
|
||||||
|
<map-layer-style name="default"/>
|
||||||
|
</map-layer-style-manager>
|
||||||
|
<auxiliaryLayer/>
|
||||||
|
<flags>
|
||||||
|
<Identifiable>1</Identifiable>
|
||||||
|
<Removable>1</Removable>
|
||||||
|
<Searchable>1</Searchable>
|
||||||
|
</flags>
|
||||||
|
<renderer-v2 type="categorizedSymbol" forceraster="0" symbollevels="0" attr="Name" enableorderby="0">
|
||||||
|
<categories>
|
||||||
|
<category symbol="0" label="Arterial" render="true" value="Arterial"/>
|
||||||
|
<category symbol="1" label="Highway" render="true" value="Highway"/>
|
||||||
|
</categories>
|
||||||
|
<symbols>
|
||||||
|
<symbol name="0" clip_to_extent="1" type="line" alpha="1" force_rhr="0">
|
||||||
|
<layer locked="0" pass="0" class="SimpleLine" enabled="1">
|
||||||
|
<prop v="square" k="capstyle"/>
|
||||||
|
<prop v="5;2" k="customdash"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="customdash_map_unit_scale"/>
|
||||||
|
<prop v="MM" k="customdash_unit"/>
|
||||||
|
<prop v="0" k="draw_inside_polygon"/>
|
||||||
|
<prop v="bevel" k="joinstyle"/>
|
||||||
|
<prop v="154,139,116,255" k="line_color"/>
|
||||||
|
<prop v="dash dot dot" k="line_style"/>
|
||||||
|
<prop v="1" k="line_width"/>
|
||||||
|
<prop v="MM" k="line_width_unit"/>
|
||||||
|
<prop v="0" k="offset"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="offset_map_unit_scale"/>
|
||||||
|
<prop v="MM" k="offset_unit"/>
|
||||||
|
<prop v="0" k="ring_filter"/>
|
||||||
|
<prop v="0" k="use_custom_dash"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="width_map_unit_scale"/>
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
</layer>
|
||||||
|
</symbol>
|
||||||
|
<symbol name="1" clip_to_extent="1" type="line" alpha="1" force_rhr="0">
|
||||||
|
<layer locked="0" pass="0" class="SimpleLine" enabled="1">
|
||||||
|
<prop v="square" k="capstyle"/>
|
||||||
|
<prop v="5;2" k="customdash"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="customdash_map_unit_scale"/>
|
||||||
|
<prop v="MM" k="customdash_unit"/>
|
||||||
|
<prop v="0" k="draw_inside_polygon"/>
|
||||||
|
<prop v="bevel" k="joinstyle"/>
|
||||||
|
<prop v="94,89,55,255" k="line_color"/>
|
||||||
|
<prop v="solid" k="line_style"/>
|
||||||
|
<prop v="1.3" k="line_width"/>
|
||||||
|
<prop v="MM" k="line_width_unit"/>
|
||||||
|
<prop v="0" k="offset"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="offset_map_unit_scale"/>
|
||||||
|
<prop v="MM" k="offset_unit"/>
|
||||||
|
<prop v="0" k="ring_filter"/>
|
||||||
|
<prop v="0" k="use_custom_dash"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="width_map_unit_scale"/>
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
</layer>
|
||||||
|
</symbol>
|
||||||
|
</symbols>
|
||||||
|
<rotation/>
|
||||||
|
<sizescale/>
|
||||||
|
</renderer-v2>
|
||||||
|
<customproperties>
|
||||||
|
<property key="embeddedWidgets/count" value="0"/>
|
||||||
|
<property key="variableNames"/>
|
||||||
|
<property key="variableValues"/>
|
||||||
|
</customproperties>
|
||||||
|
<blendMode>0</blendMode>
|
||||||
|
<featureBlendMode>0</featureBlendMode>
|
||||||
|
<layerOpacity>1</layerOpacity>
|
||||||
|
<SingleCategoryDiagramRenderer attributeLegend="1" diagramType="Pie">
|
||||||
|
<DiagramCategory minScaleDenominator="1" width="15" rotationOffset="270" lineSizeType="MM" minimumSize="0" scaleBasedVisibility="0" scaleDependency="Area" lineSizeScale="3x:0,0,0,0,0,0" penAlpha="255" enabled="0" maxScaleDenominator="1e+8" diagramOrientation="Up" barWidth="5" penColor="#000000" opacity="1" backgroundAlpha="255" sizeType="MM" penWidth="0" sizeScale="3x:0,0,0,0,0,0" backgroundColor="#ffffff" labelPlacementMethod="XHeight" height="15">
|
||||||
|
<fontProperties description="Ubuntu,13,-1,5,50,0,0,0,0,0" style=""/>
|
||||||
|
<attribute color="#000000" label="" field=""/>
|
||||||
|
</DiagramCategory>
|
||||||
|
</SingleCategoryDiagramRenderer>
|
||||||
|
<DiagramLayerSettings obstacle="0" dist="0" zIndex="0" linePlacementFlags="10" showAll="1" placement="2" priority="0">
|
||||||
|
<properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties" type="Map">
|
||||||
|
<Option name="show" type="Map">
|
||||||
|
<Option name="active" type="bool" value="true"/>
|
||||||
|
<Option name="field" type="QString" value="Name"/>
|
||||||
|
<Option name="type" type="int" value="2"/>
|
||||||
|
</Option>
|
||||||
|
</Option>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</properties>
|
||||||
|
</DiagramLayerSettings>
|
||||||
|
<geometryOptions removeDuplicateNodes="0" geometryPrecision="0">
|
||||||
|
<activeChecks/>
|
||||||
|
<checkConfiguration/>
|
||||||
|
</geometryOptions>
|
||||||
|
<fieldConfiguration>
|
||||||
|
<field name="Name">
|
||||||
|
<editWidget type="TextEdit">
|
||||||
|
<config>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="IsMultiline" type="QString" value="0"/>
|
||||||
|
<Option name="UseHtml" type="QString" value="0"/>
|
||||||
|
</Option>
|
||||||
|
</config>
|
||||||
|
</editWidget>
|
||||||
|
</field>
|
||||||
|
<field name="Value">
|
||||||
|
<editWidget type="TextEdit">
|
||||||
|
<config>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="IsMultiline" type="QString" value="0"/>
|
||||||
|
<Option name="UseHtml" type="QString" value="0"/>
|
||||||
|
</Option>
|
||||||
|
</config>
|
||||||
|
</editWidget>
|
||||||
|
</field>
|
||||||
|
</fieldConfiguration>
|
||||||
|
<aliases>
|
||||||
|
<alias name="" index="0" field="Name"/>
|
||||||
|
<alias name="" index="1" field="Value"/>
|
||||||
|
</aliases>
|
||||||
|
<excludeAttributesWMS/>
|
||||||
|
<excludeAttributesWFS/>
|
||||||
|
<defaults>
|
||||||
|
<default expression="" field="Name" applyOnUpdate="0"/>
|
||||||
|
<default expression="" field="Value" applyOnUpdate="0"/>
|
||||||
|
</defaults>
|
||||||
|
<constraints>
|
||||||
|
<constraint unique_strength="0" notnull_strength="0" field="Name" constraints="0" exp_strength="0"/>
|
||||||
|
<constraint unique_strength="0" notnull_strength="0" field="Value" constraints="0" exp_strength="0"/>
|
||||||
|
</constraints>
|
||||||
|
<constraintExpressions>
|
||||||
|
<constraint desc="" field="Name" exp=""/>
|
||||||
|
<constraint desc="" field="Value" exp=""/>
|
||||||
|
</constraintExpressions>
|
||||||
|
<expressionfields/>
|
||||||
|
<attributeactions/>
|
||||||
|
<attributetableconfig sortOrder="0" actionWidgetStyle="dropDown" sortExpression="">
|
||||||
|
<columns>
|
||||||
|
<column name="Name" type="field" hidden="0" width="-1"/>
|
||||||
|
<column name="Value" type="field" hidden="0" width="-1"/>
|
||||||
|
<column type="actions" hidden="1" width="-1"/>
|
||||||
|
<column name="Blocked" type="field" hidden="0" width="-1"/>
|
||||||
|
<column name="Situation" type="field" hidden="0" width="-1"/>
|
||||||
|
<column name="BlockStart" type="field" hidden="0" width="-1"/>
|
||||||
|
</columns>
|
||||||
|
</attributetableconfig>
|
||||||
|
<conditionalstyles>
|
||||||
|
<rowstyles/>
|
||||||
|
<fieldstyles/>
|
||||||
|
</conditionalstyles>
|
||||||
|
<editform tolerant="1"></editform>
|
||||||
|
<editforminit/>
|
||||||
|
<editforminitcodesource>0</editforminitcodesource>
|
||||||
|
<editforminitfilepath>../src/quickgui/app/qgis-data</editforminitfilepath>
|
||||||
|
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
QGIS forms can have a Python function that is called when the form is
|
||||||
|
opened.
|
||||||
|
|
||||||
|
Use this function to add extra logic to your forms.
|
||||||
|
|
||||||
|
Enter the name of the function in the "Python Init function"
|
||||||
|
field.
|
||||||
|
An example follows:
|
||||||
|
"""
|
||||||
|
from qgis.PyQt.QtWidgets import QWidget
|
||||||
|
|
||||||
|
def my_form_open(dialog, layer, feature):
|
||||||
|
geom = feature.geometry()
|
||||||
|
control = dialog.findChild(QWidget, "MyLineEdit")
|
||||||
|
]]></editforminitcode>
|
||||||
|
<featformsuppress>0</featformsuppress>
|
||||||
|
<editorlayout>generatedlayout</editorlayout>
|
||||||
|
<editable/>
|
||||||
|
<labelOnTop/>
|
||||||
|
<widgets/>
|
||||||
|
<previewExpression>COALESCE( "Name", '<NULL>' )</previewExpression>
|
||||||
|
<mapTip></mapTip>
|
||||||
|
</maplayer>
|
||||||
|
<maplayer styleCategories="AllStyleCategories" minScale="1e+8" hasScaleBasedVisibilityFlag="0" simplifyAlgorithm="0" simplifyLocal="1" readOnly="0" type="vector" autoRefreshTime="0" autoRefreshEnabled="0" simplifyMaxScale="1" simplifyDrawingTol="1" refreshOnNotifyEnabled="0" geometry="Polygon" simplifyDrawingHints="1" labelsEnabled="1" refreshOnNotifyMessage="" maxScale="1">
|
||||||
|
<extent>
|
||||||
|
<xmin>-118.92286230599032137</xmin>
|
||||||
|
<ymin>24.50786971868489061</ymin>
|
||||||
|
<xmax>-83.79001199101509201</xmax>
|
||||||
|
<ymax>46.72617265077044379</ymax>
|
||||||
|
</extent>
|
||||||
|
<id>polys20151123133114244</id>
|
||||||
|
<datasource>./polys.shp</datasource>
|
||||||
|
<keywordList>
|
||||||
|
<value></value>
|
||||||
|
</keywordList>
|
||||||
|
<layername>Land</layername>
|
||||||
|
<srs>
|
||||||
|
<spatialrefsys>
|
||||||
|
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||||
|
<srsid>3452</srsid>
|
||||||
|
<srid>4326</srid>
|
||||||
|
<authid>EPSG:4326</authid>
|
||||||
|
<description>WGS 84</description>
|
||||||
|
<projectionacronym>longlat</projectionacronym>
|
||||||
|
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||||
|
<geographicflag>true</geographicflag>
|
||||||
|
</spatialrefsys>
|
||||||
|
</srs>
|
||||||
|
<resourceMetadata>
|
||||||
|
<identifier></identifier>
|
||||||
|
<parentidentifier></parentidentifier>
|
||||||
|
<language></language>
|
||||||
|
<type></type>
|
||||||
|
<title></title>
|
||||||
|
<abstract></abstract>
|
||||||
|
<links/>
|
||||||
|
<fees></fees>
|
||||||
|
<encoding></encoding>
|
||||||
|
<crs>
|
||||||
|
<spatialrefsys>
|
||||||
|
<proj4></proj4>
|
||||||
|
<srsid>0</srsid>
|
||||||
|
<srid>0</srid>
|
||||||
|
<authid></authid>
|
||||||
|
<description></description>
|
||||||
|
<projectionacronym></projectionacronym>
|
||||||
|
<ellipsoidacronym></ellipsoidacronym>
|
||||||
|
<geographicflag>false</geographicflag>
|
||||||
|
</spatialrefsys>
|
||||||
|
</crs>
|
||||||
|
<extent/>
|
||||||
|
</resourceMetadata>
|
||||||
|
<provider encoding="UTF-8">ogr</provider>
|
||||||
|
<vectorjoins/>
|
||||||
|
<layerDependencies/>
|
||||||
|
<dataDependencies/>
|
||||||
|
<legend type="default-vector"/>
|
||||||
|
<expressionfields/>
|
||||||
|
<map-layer-style-manager current="default">
|
||||||
|
<map-layer-style name="default"/>
|
||||||
|
</map-layer-style-manager>
|
||||||
|
<auxiliaryLayer/>
|
||||||
|
<flags>
|
||||||
|
<Identifiable>1</Identifiable>
|
||||||
|
<Removable>1</Removable>
|
||||||
|
<Searchable>1</Searchable>
|
||||||
|
</flags>
|
||||||
|
<renderer-v2 type="categorizedSymbol" forceraster="0" symbollevels="0" attr="Name" enableorderby="0">
|
||||||
|
<categories>
|
||||||
|
<category symbol="0" label="Dam" render="true" value="Dam"/>
|
||||||
|
<category symbol="1" label="Lake" render="true" value="Lake"/>
|
||||||
|
</categories>
|
||||||
|
<symbols>
|
||||||
|
<symbol name="0" clip_to_extent="1" type="fill" alpha="1" force_rhr="0">
|
||||||
|
<layer locked="0" pass="0" class="SimpleFill" enabled="1">
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="border_width_map_unit_scale"/>
|
||||||
|
<prop v="118,191,227,132" k="color"/>
|
||||||
|
<prop v="bevel" k="joinstyle"/>
|
||||||
|
<prop v="0,0" k="offset"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="offset_map_unit_scale"/>
|
||||||
|
<prop v="MM" k="offset_unit"/>
|
||||||
|
<prop v="31,120,180,255" k="outline_color"/>
|
||||||
|
<prop v="solid" k="outline_style"/>
|
||||||
|
<prop v="0.66" k="outline_width"/>
|
||||||
|
<prop v="MM" k="outline_width_unit"/>
|
||||||
|
<prop v="solid" k="style"/>
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
</layer>
|
||||||
|
</symbol>
|
||||||
|
<symbol name="1" clip_to_extent="1" type="fill" alpha="1" force_rhr="0">
|
||||||
|
<layer locked="0" pass="0" class="SimpleFill" enabled="1">
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="border_width_map_unit_scale"/>
|
||||||
|
<prop v="110,194,217,255" k="color"/>
|
||||||
|
<prop v="bevel" k="joinstyle"/>
|
||||||
|
<prop v="0,0" k="offset"/>
|
||||||
|
<prop v="3x:0,0,0,0,0,0" k="offset_map_unit_scale"/>
|
||||||
|
<prop v="MM" k="offset_unit"/>
|
||||||
|
<prop v="144,144,144,255" k="outline_color"/>
|
||||||
|
<prop v="solid" k="outline_style"/>
|
||||||
|
<prop v="0.66" k="outline_width"/>
|
||||||
|
<prop v="MM" k="outline_width_unit"/>
|
||||||
|
<prop v="solid" k="style"/>
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
</layer>
|
||||||
|
</symbol>
|
||||||
|
</symbols>
|
||||||
|
<rotation/>
|
||||||
|
<sizescale/>
|
||||||
|
</renderer-v2>
|
||||||
|
<customproperties>
|
||||||
|
<property key="embeddedWidgets/count" value="0"/>
|
||||||
|
<property key="variableNames"/>
|
||||||
|
<property key="variableValues"/>
|
||||||
|
</customproperties>
|
||||||
|
<blendMode>0</blendMode>
|
||||||
|
<featureBlendMode>0</featureBlendMode>
|
||||||
|
<layerOpacity>1</layerOpacity>
|
||||||
|
<SingleCategoryDiagramRenderer attributeLegend="1" diagramType="Pie">
|
||||||
|
<DiagramCategory minScaleDenominator="1" width="15" rotationOffset="270" lineSizeType="MM" minimumSize="0" scaleBasedVisibility="0" scaleDependency="Area" lineSizeScale="3x:0,0,0,0,0,0" penAlpha="255" enabled="0" maxScaleDenominator="1e+8" diagramOrientation="Up" barWidth="5" penColor="#000000" opacity="1" backgroundAlpha="255" sizeType="MM" penWidth="0" sizeScale="3x:0,0,0,0,0,0" backgroundColor="#ffffff" labelPlacementMethod="XHeight" height="15">
|
||||||
|
<fontProperties description="Ubuntu,13,-1,5,50,0,0,0,0,0" style=""/>
|
||||||
|
<attribute color="#000000" label="" field=""/>
|
||||||
|
</DiagramCategory>
|
||||||
|
</SingleCategoryDiagramRenderer>
|
||||||
|
<DiagramLayerSettings obstacle="0" dist="0" zIndex="0" linePlacementFlags="10" showAll="1" placement="0" priority="0">
|
||||||
|
<properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties" type="Map">
|
||||||
|
<Option name="show" type="Map">
|
||||||
|
<Option name="active" type="bool" value="true"/>
|
||||||
|
<Option name="field" type="QString" value="Name"/>
|
||||||
|
<Option name="type" type="int" value="2"/>
|
||||||
|
</Option>
|
||||||
|
</Option>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</properties>
|
||||||
|
</DiagramLayerSettings>
|
||||||
|
<geometryOptions removeDuplicateNodes="0" geometryPrecision="0">
|
||||||
|
<activeChecks/>
|
||||||
|
<checkConfiguration/>
|
||||||
|
</geometryOptions>
|
||||||
|
<fieldConfiguration>
|
||||||
|
<field name="Name">
|
||||||
|
<editWidget type="ValueMap">
|
||||||
|
<config>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="map" type="Map">
|
||||||
|
<Option name="Dam" type="QString" value="Dam"/>
|
||||||
|
<Option name="Lake" type="QString" value="Lake"/>
|
||||||
|
</Option>
|
||||||
|
</Option>
|
||||||
|
</config>
|
||||||
|
</editWidget>
|
||||||
|
</field>
|
||||||
|
<field name="Value">
|
||||||
|
<editWidget type="TextEdit">
|
||||||
|
<config>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="IsMultiline" type="QString" value="0"/>
|
||||||
|
<Option name="UseHtml" type="QString" value="0"/>
|
||||||
|
</Option>
|
||||||
|
</config>
|
||||||
|
</editWidget>
|
||||||
|
</field>
|
||||||
|
</fieldConfiguration>
|
||||||
|
<aliases>
|
||||||
|
<alias name="" index="0" field="Name"/>
|
||||||
|
<alias name="" index="1" field="Value"/>
|
||||||
|
</aliases>
|
||||||
|
<excludeAttributesWMS/>
|
||||||
|
<excludeAttributesWFS/>
|
||||||
|
<defaults>
|
||||||
|
<default expression="" field="Name" applyOnUpdate="0"/>
|
||||||
|
<default expression="" field="Value" applyOnUpdate="0"/>
|
||||||
|
</defaults>
|
||||||
|
<constraints>
|
||||||
|
<constraint unique_strength="0" notnull_strength="0" field="Name" constraints="0" exp_strength="0"/>
|
||||||
|
<constraint unique_strength="0" notnull_strength="0" field="Value" constraints="0" exp_strength="0"/>
|
||||||
|
</constraints>
|
||||||
|
<constraintExpressions>
|
||||||
|
<constraint desc="" field="Name" exp=""/>
|
||||||
|
<constraint desc="" field="Value" exp=""/>
|
||||||
|
</constraintExpressions>
|
||||||
|
<expressionfields/>
|
||||||
|
<attributeactions>
|
||||||
|
<defaultAction key="Canvas" value="{00000000-0000-0000-0000-000000000000}"/>
|
||||||
|
</attributeactions>
|
||||||
|
<attributetableconfig sortOrder="0" actionWidgetStyle="dropDown" sortExpression="">
|
||||||
|
<columns>
|
||||||
|
<column name="Name" type="field" hidden="0" width="-1"/>
|
||||||
|
<column name="Value" type="field" hidden="0" width="-1"/>
|
||||||
|
<column type="actions" hidden="1" width="-1"/>
|
||||||
|
</columns>
|
||||||
|
</attributetableconfig>
|
||||||
|
<conditionalstyles>
|
||||||
|
<rowstyles/>
|
||||||
|
<fieldstyles/>
|
||||||
|
</conditionalstyles>
|
||||||
|
<editform tolerant="1"></editform>
|
||||||
|
<editforminit/>
|
||||||
|
<editforminitcodesource>0</editforminitcodesource>
|
||||||
|
<editforminitfilepath>../src/quickgui/app/qgis-data</editforminitfilepath>
|
||||||
|
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
QGIS forms can have a Python function that is called when the form is
|
||||||
|
opened.
|
||||||
|
|
||||||
|
Use this function to add extra logic to your forms.
|
||||||
|
|
||||||
|
Enter the name of the function in the "Python Init function"
|
||||||
|
field.
|
||||||
|
An example follows:
|
||||||
|
"""
|
||||||
|
from qgis.PyQt.QtWidgets import QWidget
|
||||||
|
|
||||||
|
def my_form_open(dialog, layer, feature):
|
||||||
|
geom = feature.geometry()
|
||||||
|
control = dialog.findChild(QWidget, "MyLineEdit")
|
||||||
|
]]></editforminitcode>
|
||||||
|
<featformsuppress>0</featformsuppress>
|
||||||
|
<editorlayout>generatedlayout</editorlayout>
|
||||||
|
<editable/>
|
||||||
|
<labelOnTop/>
|
||||||
|
<widgets/>
|
||||||
|
<previewExpression>COALESCE( "Name", '<NULL>' )</previewExpression>
|
||||||
|
<mapTip></mapTip>
|
||||||
|
</maplayer>
|
||||||
|
</projectlayers>
|
||||||
|
<layerorder>
|
||||||
|
<layer id="polys20151123133114244"/>
|
||||||
|
<layer id="lines20151123133101198"/>
|
||||||
|
</layerorder>
|
||||||
|
<properties>
|
||||||
|
<DefaultStyles>
|
||||||
|
<AlphaInt type="int">255</AlphaInt>
|
||||||
|
<ColorRamp type="QString"></ColorRamp>
|
||||||
|
<Fill type="QString"></Fill>
|
||||||
|
<Line type="QString"></Line>
|
||||||
|
<Marker type="QString"></Marker>
|
||||||
|
<Opacity type="double">1</Opacity>
|
||||||
|
<RandomColors type="bool">true</RandomColors>
|
||||||
|
</DefaultStyles>
|
||||||
|
<Digitizing>
|
||||||
|
<AvoidIntersectionsList type="QStringList"/>
|
||||||
|
<DefaultSnapTolerance type="double">20</DefaultSnapTolerance>
|
||||||
|
<DefaultSnapToleranceUnit type="int">1</DefaultSnapToleranceUnit>
|
||||||
|
<DefaultSnapType type="QString">to vertex and segment</DefaultSnapType>
|
||||||
|
<LayerSnapToList type="QStringList">
|
||||||
|
<value>to_vertex_and_segment</value>
|
||||||
|
<value>to_vertex_and_segment</value>
|
||||||
|
<value>to_vertex_and_segment</value>
|
||||||
|
</LayerSnapToList>
|
||||||
|
<LayerSnappingEnabledList type="QStringList">
|
||||||
|
<value>enabled</value>
|
||||||
|
<value>enabled</value>
|
||||||
|
<value>enabled</value>
|
||||||
|
</LayerSnappingEnabledList>
|
||||||
|
<LayerSnappingList type="QStringList">
|
||||||
|
<value>lines20151123133101198</value>
|
||||||
|
<value>points20151123133104693</value>
|
||||||
|
<value>polys20151123133114244</value>
|
||||||
|
</LayerSnappingList>
|
||||||
|
<LayerSnappingToleranceList type="QStringList">
|
||||||
|
<value>20.000000</value>
|
||||||
|
<value>20.000000</value>
|
||||||
|
<value>20.000000</value>
|
||||||
|
</LayerSnappingToleranceList>
|
||||||
|
<LayerSnappingToleranceUnitList type="QStringList">
|
||||||
|
<value>1</value>
|
||||||
|
<value>1</value>
|
||||||
|
<value>1</value>
|
||||||
|
</LayerSnappingToleranceUnitList>
|
||||||
|
<SnappingMode type="QString">current_layer</SnappingMode>
|
||||||
|
</Digitizing>
|
||||||
|
<Gui>
|
||||||
|
<CanvasColorBluePart type="int">255</CanvasColorBluePart>
|
||||||
|
<CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
|
||||||
|
<CanvasColorRedPart type="int">255</CanvasColorRedPart>
|
||||||
|
<SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
|
||||||
|
<SelectionColorBluePart type="int">0</SelectionColorBluePart>
|
||||||
|
<SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
|
||||||
|
<SelectionColorRedPart type="int">255</SelectionColorRedPart>
|
||||||
|
</Gui>
|
||||||
|
<Identify>
|
||||||
|
<disabledLayers type="QStringList"/>
|
||||||
|
</Identify>
|
||||||
|
<Legend>
|
||||||
|
<filterByMap type="bool">false</filterByMap>
|
||||||
|
</Legend>
|
||||||
|
<Macros>
|
||||||
|
<pythonCode type="QString"></pythonCode>
|
||||||
|
</Macros>
|
||||||
|
<Measure>
|
||||||
|
<Ellipsoid type="QString">WGS84</Ellipsoid>
|
||||||
|
</Measure>
|
||||||
|
<Measurement>
|
||||||
|
<AreaUnits type="QString">m2</AreaUnits>
|
||||||
|
<DistanceUnits type="QString">meters</DistanceUnits>
|
||||||
|
</Measurement>
|
||||||
|
<PAL>
|
||||||
|
<CandidatesLine type="int">50</CandidatesLine>
|
||||||
|
<CandidatesPoint type="int">16</CandidatesPoint>
|
||||||
|
<CandidatesPolygon type="int">30</CandidatesPolygon>
|
||||||
|
<DrawRectOnly type="bool">false</DrawRectOnly>
|
||||||
|
<SearchMethod type="int">0</SearchMethod>
|
||||||
|
<ShowingAllLabels type="bool">false</ShowingAllLabels>
|
||||||
|
<ShowingCandidates type="bool">false</ShowingCandidates>
|
||||||
|
<ShowingPartialsLabels type="bool">true</ShowingPartialsLabels>
|
||||||
|
<TextFormat type="int">0</TextFormat>
|
||||||
|
</PAL>
|
||||||
|
<Paths>
|
||||||
|
<Absolute type="bool">false</Absolute>
|
||||||
|
</Paths>
|
||||||
|
<PositionPrecision>
|
||||||
|
<Automatic type="bool">true</Automatic>
|
||||||
|
<DecimalPlaces type="int">2</DecimalPlaces>
|
||||||
|
<DegreeFormat type="QString">MU</DegreeFormat>
|
||||||
|
</PositionPrecision>
|
||||||
|
<SpatialRefSys>
|
||||||
|
<ProjectCRSID type="int">3452</ProjectCRSID>
|
||||||
|
<ProjectCRSProj4String type="QString">+proj=longlat +datum=WGS84 +no_defs</ProjectCRSProj4String>
|
||||||
|
<ProjectCrs type="QString">EPSG:4326</ProjectCrs>
|
||||||
|
<ProjectionsEnabled type="int">1</ProjectionsEnabled>
|
||||||
|
</SpatialRefSys>
|
||||||
|
<Variables>
|
||||||
|
<variableNames type="QStringList"/>
|
||||||
|
<variableValues type="QStringList"/>
|
||||||
|
</Variables>
|
||||||
|
<WCSLayers type="QStringList"/>
|
||||||
|
<WCSUrl type="QString"></WCSUrl>
|
||||||
|
<WFSLayers type="QStringList"/>
|
||||||
|
<WFSTLayers>
|
||||||
|
<Delete type="QStringList"/>
|
||||||
|
<Insert type="QStringList"/>
|
||||||
|
<Update type="QStringList"/>
|
||||||
|
</WFSTLayers>
|
||||||
|
<WFSUrl type="QString"></WFSUrl>
|
||||||
|
<WMSAccessConstraints type="QString">None</WMSAccessConstraints>
|
||||||
|
<WMSAddWktGeometry type="bool">false</WMSAddWktGeometry>
|
||||||
|
<WMSContactMail type="QString"></WMSContactMail>
|
||||||
|
<WMSContactOrganization type="QString"></WMSContactOrganization>
|
||||||
|
<WMSContactPerson type="QString"></WMSContactPerson>
|
||||||
|
<WMSContactPhone type="QString"></WMSContactPhone>
|
||||||
|
<WMSContactPosition type="QString"></WMSContactPosition>
|
||||||
|
<WMSFees type="QString">conditions unknown</WMSFees>
|
||||||
|
<WMSImageQuality type="int">90</WMSImageQuality>
|
||||||
|
<WMSKeywordList type="QStringList">
|
||||||
|
<value></value>
|
||||||
|
</WMSKeywordList>
|
||||||
|
<WMSMaxAtlasFeatures type="int">1</WMSMaxAtlasFeatures>
|
||||||
|
<WMSOnlineResource type="QString"></WMSOnlineResource>
|
||||||
|
<WMSPrecision type="QString">8</WMSPrecision>
|
||||||
|
<WMSRootName type="QString"></WMSRootName>
|
||||||
|
<WMSSegmentizeFeatureInfoGeometry type="bool">false</WMSSegmentizeFeatureInfoGeometry>
|
||||||
|
<WMSServiceAbstract type="QString"></WMSServiceAbstract>
|
||||||
|
<WMSServiceCapabilities type="bool">false</WMSServiceCapabilities>
|
||||||
|
<WMSServiceTitle type="QString"></WMSServiceTitle>
|
||||||
|
<WMSUrl type="QString"></WMSUrl>
|
||||||
|
<WMSUseLayerIDs type="bool">false</WMSUseLayerIDs>
|
||||||
|
<WMTSGrids>
|
||||||
|
<CRS type="QStringList"/>
|
||||||
|
<Config type="QStringList"/>
|
||||||
|
</WMTSGrids>
|
||||||
|
<WMTSJpegLayers>
|
||||||
|
<Group type="QStringList"/>
|
||||||
|
<Layer type="QStringList"/>
|
||||||
|
<Project type="bool">false</Project>
|
||||||
|
</WMTSJpegLayers>
|
||||||
|
<WMTSLayers>
|
||||||
|
<Group type="QStringList"/>
|
||||||
|
<Layer type="QStringList"/>
|
||||||
|
<Project type="bool">false</Project>
|
||||||
|
</WMTSLayers>
|
||||||
|
<WMTSMinScale type="int">5000</WMTSMinScale>
|
||||||
|
<WMTSPngLayers>
|
||||||
|
<Group type="QStringList"/>
|
||||||
|
<Layer type="QStringList"/>
|
||||||
|
<Project type="bool">false</Project>
|
||||||
|
</WMTSPngLayers>
|
||||||
|
<WMTSUrl type="QString"></WMTSUrl>
|
||||||
|
<ddt2>
|
||||||
|
<designs type="QString"></designs>
|
||||||
|
</ddt2>
|
||||||
|
</properties>
|
||||||
|
<visibility-presets/>
|
||||||
|
<transformContext/>
|
||||||
|
<projectMetadata>
|
||||||
|
<identifier></identifier>
|
||||||
|
<parentidentifier></parentidentifier>
|
||||||
|
<language></language>
|
||||||
|
<type></type>
|
||||||
|
<title></title>
|
||||||
|
<abstract></abstract>
|
||||||
|
<contact>
|
||||||
|
<name></name>
|
||||||
|
<organization></organization>
|
||||||
|
<position></position>
|
||||||
|
<voice></voice>
|
||||||
|
<fax></fax>
|
||||||
|
<email></email>
|
||||||
|
<role></role>
|
||||||
|
</contact>
|
||||||
|
<links/>
|
||||||
|
<author></author>
|
||||||
|
<creation>2000-01-01T00:00:00</creation>
|
||||||
|
</projectMetadata>
|
||||||
|
<Annotations/>
|
||||||
|
<Layouts/>
|
||||||
|
</qgis>
|