Skip to content

Commit 333be4a

Browse files
authored
Merge pull request #150 from maptiler/v2-dev
Plugin v2 Closes #105. Closes #108. Closes #115. Closes #131. Closes #133. Closes #138. Closes #139. Closes #143. Closes #146.
2 parents 99a8d56 + e48cafa commit 333be4a

File tree

7 files changed

+1555
-811
lines changed

7 files changed

+1555
-811
lines changed

README.md

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,9 @@ Then MapTiler should be added to your QGIS Browser.
3535

3636
<img src='imgs/readme_01.png'>
3737

38-
### Requirements
38+
## Requirements
3939

40-
You need to have installed Python Pillow [Pillow](https://pillow.readthedocs.io/en/stable/)
41-
library to use MapTiler plugin.
42-
43-
On Debian/Ubuntu systems you can install it by:
44-
45-
`python3 -m pip install Pillow`
46-
47-
### Known issue for macOS users
48-
49-
Sometimes macOS users get following or similar error when running MapTiler plugin:
50-
```
51-
ImportError: dlopen(/Applications/QGIS.app/Contents/MacOS/lib/python3.7/site-packages/Pillow-7.2.0-py3.7-macosx-10.13.0-x86_64.egg/PIL/_imaging.cpython-37m-darwin.so, 2): Library not loaded: /opt/X11/lib/libxcb.1.dylib
52-
Referenced from: /Applications/QGIS.app/Contents/MacOS/lib/python3.7/site-packages/Pillow-7.2.0-py3.7-macosx-10.13.0-x86_64.egg/PIL/_imaging.cpython-37m-darwin.so
53-
Reason: image not found
54-
```
55-
56-
macOS users need to upgrade their Pillow library from QGIS bundled Python:
57-
```
58-
/Applications/QGIS.app/Contents/MacOS/bin/pip3 install pillow -U
59-
```
60-
61-
After running this command and restarting QGIS, MapTiler plugin should work.
40+
For plugin version 2.0, you need QGIS 3.16 or higher.
6241

6342
---
6443

@@ -95,6 +74,7 @@ MapTiler plugin supports loading maps via both vector and raster tiles. You can
9574
You can choose the default type of tiles by checking/unchecking `Use vector tiles by default` in the Account dialog window.
9675

9776
Vector tiles support requires QGIS 3.13 or higher.
77+
For the plugin version 2.0 and higher you need QGIS 3.16 or higher.
9878

9979
You can read about the difference between vector and raster tiles here [https://www.maptiler.com/news/2019/02/what-are-vector-tiles-and-why-you-should-care/](https://www.maptiler.com/news/2019/02/what-are-vector-tiles-and-why-you-should-care/?utm_source=github.com&utm_medium=referral&utm_campaign=qgis-plugin)
10080

@@ -141,5 +121,3 @@ The native vector tiles python APIs in QGIS was developed by @wonder-sk from [Lu
141121
If you have any idea or trouble, please [post an Issue](https://github.com/maptiler/qgis-maptiler-plugin/issues) first.
142122

143123
We very much welcome contributions from all developers out there. This project is a community-driven open-source tool - please help us to make it better.
144-
145-

browser_mapitem.py

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import os
2-
import sip
32
import json
43
import requests
54
import webbrowser
6-
import shutil
7-
from qgis.PyQt.QtGui import QIcon
8-
from qgis.PyQt.QtWidgets import QAction, QMessageBox
5+
96
from qgis.core import *
7+
from qgis.PyQt.QtGui import QIcon
8+
from qgis.PyQt.QtWidgets import QAction, QMessageBox, QPushButton
9+
from qgis.gui import QgsMessageViewer
10+
from qgis.utils import iface
1011

1112
from .gl2qgis import converter
1213

@@ -201,7 +202,6 @@ def _add_vector_to_canvas(self, data_key='vector'):
201202
self._add_vtlayer_from_tile_json(
202203
tile_json_data, node_map, attribution_text)
203204

204-
205205
def _add_vtlayer_from_style_json(self,
206206
style_json_data: dict,
207207
target_node: QgsLayerTreeGroup,
@@ -211,27 +211,41 @@ def _add_vtlayer_from_style_json(self,
211211
os.makedirs(SPRITES_PATH, exist_ok=True)
212212
converter.write_sprite_imgs_from_style_json(style_json_data, SPRITES_PATH)
213213

214+
# Context
215+
context = QgsMapBoxGlStyleConversionContext()
216+
context.setTargetUnit(QgsUnitTypes.RenderMillimeters)
217+
context.setPixelSizeConversionFactor(0.264583) # 25.4 / 96.0
218+
# context.setTargetUnit(QgsUnitTypes.RenderPixels)
219+
# context.setPixelSizeConversionFactor(1)
220+
214221
# Add other layers from sources
215222
sources = converter.get_sources_dict_from_style_json(
216223
style_json_data)
217224
ordered_sources = {k: v for k, v in sorted(sources.items(), key=lambda item: item[1]["order"])}
218225
for source_id, source_data in ordered_sources.items():
219226
zxy_url = source_data["zxy_url"]
220227
name = source_data["name"]
221-
url = f"type=xyz&url={zxy_url}"
228+
max_zoom = source_data["maxzoom"]
229+
url = f"type=xyz&url={zxy_url}&zmax={max_zoom}"
222230
if source_data["type"] == "vector":
223231
vector = QgsVectorTileLayer(url, name)
224-
renderer, labeling = converter.get_renderer_labeling(
225-
source_id, style_json_data)
232+
renderer, labeling, candidate_warnings = converter.convert(source_id, style_json_data, context)
226233
vector.setLabeling(labeling)
227234
vector.setRenderer(renderer)
228235
vector.setAttribution(attribution_text)
229236
proj.addMapLayer(vector, False)
230237
target_node.insertLayer(source_data["order"], vector)
231238
elif source_data["type"] == "raster-dem":
232-
# TODO solve layer style
233-
raster = QgsRasterLayer(url, name, "wms")
234-
raster.setAttribution(attribution_text)
239+
# TODO remove this after RGB tiles implementation (Outdoor)
240+
if source_data.get("name") == "Terrain RGB" and "https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=" in source_data.get("zxy_url"):
241+
url = f"zmin=0&zmax=12&type=xyz&url={source_data.get('zxy_url').replace('terrain-rgb', 'hillshades')}"
242+
raster = QgsRasterLayer(url, "hillshades", "wms")
243+
renderer = raster.renderer().clone()
244+
renderer.setOpacity(0.2)
245+
raster.setRenderer(renderer)
246+
else:
247+
raster = QgsRasterLayer(url, name, "wms")
248+
raster.setAttribution(attribution_text)
235249
proj.addMapLayer(raster, False)
236250
target_node.insertLayer(source_data["order"], raster)
237251
elif source_data["type"] == "raster":
@@ -240,8 +254,7 @@ def _add_vtlayer_from_style_json(self,
240254
min_zoom = source_data["minzoom"]
241255
max_zoom = source_data["maxzoom"]
242256
url = f"zmin={min_zoom}&zmax={max_zoom}&type=xyz&url={zxy_url}"
243-
rlayers = converter.get_source_layers_by(
244-
source_id, style_json_data)
257+
rlayers = converter.get_source_layers_by(source_id, style_json_data)
245258
for rlayer_json in rlayers:
246259
layer_id = rlayer_json.get("id", "NO_NAME")
247260
raster = QgsRasterLayer(url, layer_id, "wms")
@@ -260,6 +273,37 @@ def _add_vtlayer_from_style_json(self,
260273
proj.addMapLayer(raster, False)
261274
target_node.insertLayer(source_data["order"], raster)
262275

276+
# Print conversion warnings
277+
# Removed known warnings
278+
if bool(candidate_warnings):
279+
warnings = list()
280+
for candidate in candidate_warnings:
281+
if "Could not retrieve sprite ''" in candidate:
282+
continue
283+
warnings.append(candidate)
284+
# Print warnings during conversion
285+
if bool(warnings):
286+
widget = iface.messageBar().createMessage("Vector tiles:",
287+
"Style could not be completely converted")
288+
button = QPushButton(widget)
289+
button.setText("Details")
290+
291+
def show_warnings():
292+
warnings_dlg = QgsMessageViewer()
293+
warnings_dlg.setTitle("Vector Tiles")
294+
html_text = "<p>The following warnings were generated while converting the vector tile style:</p><ul>"
295+
for cw in warnings:
296+
# Skip known issues
297+
298+
html_text += f"<li>{cw}</li>"
299+
html_text += "</ul>"
300+
warnings_dlg.setMessage(html_text, 1)
301+
warnings_dlg.showMessage()
302+
303+
button.pressed.connect(show_warnings)
304+
widget.layout().addWidget(button)
305+
iface.messageBar().pushWidget(widget, Qgis.Warning)
306+
263307
# Add background layer as last if exists
264308
bg_renderer = converter.get_bg_renderer(style_json_data)
265309
if bg_renderer:
@@ -308,22 +352,6 @@ def _get_attribution_text(self, data_key, apikey) -> str:
308352

309353
return attribution_text
310354

311-
def _get_attr_of_custom_json(self, custom_json_data) -> str:
312-
attribution_text = ""
313-
314-
url_endpoint = custom_json_url.split("?")[0]
315-
# get attribution from custom tiles or style json
316-
if url_endpoint.endswith("style.json"):
317-
sources = custom_json_data.get("sources")
318-
maptiler_attribution = sources.get("maptiler_attribution")
319-
if maptiler_attribution:
320-
attribution = maptiler_attribution.get("attribution", "")
321-
attribution_text = str(attribution)
322-
else:
323-
attribution_text = custom_json_data.get("attribution", "")
324-
325-
return attribution_text
326-
327355
def _add_custom_to_canvas(self):
328356
json_url = self._dataset['custom']
329357
if json_url.endswith("?key="):

gl2qgis/converter.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
import io
1717
import os
1818

19-
from .gl2qgis import parse_layers, parse_background, parse_interpolate_list_by_zoom
20-
from .gl2qgis import parse_interpolate_opacity_by_zoom, PropertyType
19+
from .gl2qgis import parse_layers, parse_background
2120
from qgis.PyQt.QtWidgets import QMessageBox
21+
from qgis.core import QgsMapBoxGlStyleConversionContext
2222

2323

2424
def get_sources_dict_from_style_json(style_json_data: dict) -> dict:
@@ -93,16 +93,9 @@ def get_style_json(style_json_url: str) -> dict:
9393
raise Exception(f"Invalid url: {style_json_url}")
9494

9595

96-
def get_renderer_labeling(source_name: str, style_json_data: dict):
97-
layers = style_json_data.get("layers")
98-
source_layers = []
99-
for layer in layers:
100-
if "source" not in layer or layer["source"] != source_name:
101-
continue
102-
source_layers.append(layer)
103-
104-
renderer, labeling = parse_layers(source_layers, style_json_data.get('id'))
105-
return renderer, labeling
96+
def convert(source_name: str, style_json_data: dict, context: QgsMapBoxGlStyleConversionContext):
97+
renderer, labeling, warnings = parse_layers(source_name, style_json_data, context)
98+
return renderer, labeling, warnings
10699

107100

108101
def get_bg_renderer(style_json_data: dict):

0 commit comments

Comments
 (0)