Basemap-Legende: Rand für weiße Flächen ohne Kontur (#92)

Die Basemap-Styles „Platz“ (Verkehrsfläche, weitere Nutzung) haben eine rein weiße Füllung
ohne Umrandung und waren auf dem weißen Legendenhintergrund unsichtbar. baue_symbole gibt
solchen Flächensymbolen jetzt in der Legende eine dünne graue Randlinie (0,15 mm). Erkannt
wird das an Füllfarbe und fehlender Kontur (braucht_legendenrand), nicht an Style-Namen; der
Basemap-Layer in der Karte bleibt unverändert. Wrapper: QgsSimpleLineSymbolLayer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 12:49:01 +02:00
co-authored by Claude Opus 5.5
parent 1dc19d1324
commit 7465904121
4 changed files with 188 additions and 0 deletions
+69
View File
@@ -34,6 +34,7 @@ from sn_basis.functions.qgiscore_wrapper import (
QgsLegendRenderer,
QgsProperty,
QgsRendererCategory,
QgsSimpleLineSymbolLayer,
QgsSymbolLayerUtils,
QgsUnitTypes,
QgsVectorLayer,
@@ -62,6 +63,13 @@ LAYOUT_HILFSLAYER = "sn_basemap_hilfslayer"
HILFSLAYER_KENNUNG = "sn_basemap_legende"
_GEOMETRIE_JE_SYMBOLTYP = {0: "Point", 1: "LineString", 2: "Polygon"}
# Legendenrand für weiße Flächen ohne Kontur (Basis #92)
LEGENDENRAND_BREITE_MM = 0.15
LEGENDENRAND_FARBE = "150,150,150,255"
# Ab diesem Wert je Farbkanal gilt eine Farbe auf weißem Legendenhintergrund als unsichtbar.
HELL_AB = 240
DURCHSICHTIG_BIS = 25
_ZOOM_VARIABLEN = {"vector_tile_zoom", "zoom_level"}
_VARIABLE = re.compile(r"@([A-Za-z_][A-Za-z0-9_]*)")
@@ -181,10 +189,71 @@ def baue_symbole(layer: Any, eintraege: list, zoom_level: int, vector_tile_zoom:
basis.appendSymbolLayer(symbol_layer.clone())
if basis is not None:
friere_zoom_ein(basis, zoom_level, vector_tile_zoom)
ergaenze_legendenrand(basis)
symbole[eintrag.schluessel] = basis
return symbole
def _ist_unsichtbar(farbe: tuple) -> bool:
"""Ob eine RGBA-Farbe auf weißem Legendenhintergrund praktisch nicht zu sehen ist."""
rot, gruen, blau, alpha = farbe
return alpha <= DURCHSICHTIG_BIS or min(rot, gruen, blau) >= HELL_AB
def braucht_legendenrand(ebenen: list[dict]) -> bool:
"""Ob ein Flächensymbol in der Legende einen Rand braucht.
``ebenen`` beschreibt die Symbolebenen: ``art`` (``fuellung``, ``linie``, ``sonst``), ``farbe``
(RGBA) und bei Füllungen ``rand`` (RGBA oder ``None`` ohne Kontur). Ein Rand ist nötig, wenn
alle Ebenen auf weißem Hintergrund unsichtbar sind – z. B. die weiße Fläche „Platz“.
"""
if not ebenen:
return False
for ebene in ebenen:
if ebene.get("art") not in ("fuellung", "linie") or not _ist_unsichtbar(ebene["farbe"]):
return False
if ebene.get("rand") is not None and not _ist_unsichtbar(ebene["rand"]):
return False
return True
def _rgba(farbe: Any) -> tuple:
return farbe.red(), farbe.green(), farbe.blue(), farbe.alpha()
def _ebenen_beschreiben(symbol: Any) -> list[dict]:
ebenen = []
for ebene in symbol.symbolLayers():
art = ebene.layerType()
if art == "SimpleFill":
ohne_kontur = _enum_int(ebene.strokeStyle()) == 0 # Qt.NoPen
ebenen.append({"art": "fuellung", "farbe": _rgba(ebene.color()),
"rand": None if ohne_kontur else _rgba(ebene.strokeColor())})
elif art == "SimpleLine":
ebenen.append({"art": "linie", "farbe": _rgba(ebene.color())})
else:
ebenen.append({"art": "sonst"})
return ebenen
def ergaenze_legendenrand(symbol: Any) -> bool:
"""Gibt einem praktisch weißen Flächensymbol ohne Kontur einen dünnen grauen Rand (nur Legende).
Returns
-------
bool
Ob ein Rand ergänzt wurde.
"""
if _enum_int(symbol.type()) != 2 or not braucht_legendenrand(_ebenen_beschreiben(symbol)):
return False
symbol.appendSymbolLayer(QgsSimpleLineSymbolLayer.create({
"line_color": LEGENDENRAND_FARBE,
"line_width": str(LEGENDENRAND_BREITE_MM),
"line_width_unit": "MM",
}))
return True
def vorschau_icon(symbol: Any) -> Any:
if symbol is None:
return None